chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
<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>hertzbeat</artifactId>
|
||||
<groupId>org.apache.hertzbeat</groupId>
|
||||
<version>2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>hertzbeat-common-spring</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
<description>Spring Boot, configuration, validation, and JPA integration built on common-core.</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- hertzbeat-common-core dependency -->
|
||||
<dependency>
|
||||
<groupId>org.apache.hertzbeat</groupId>
|
||||
<artifactId>hertzbeat-common-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- spring -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
<!-- jpa -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<!-- validation -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<!-- swagger -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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.cache;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import org.apache.hertzbeat.common.constants.CommonConstants;
|
||||
import org.apache.hertzbeat.common.entity.alerter.AlertDefine;
|
||||
import org.apache.hertzbeat.common.entity.alerter.AlertSilence;
|
||||
import org.apache.hertzbeat.common.entity.alerter.NoticeRule;
|
||||
|
||||
/**
|
||||
* common cache factory
|
||||
*/
|
||||
public final class CacheFactory {
|
||||
private CacheFactory() {}
|
||||
|
||||
private static final CommonCacheService<String, Object> COMMON_CACHE =
|
||||
new CaffeineCacheServiceImpl<>(1, 1000, Duration.ofDays(1), false);
|
||||
|
||||
/**
|
||||
* get notice cache
|
||||
* @return caffeine cache
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static List<NoticeRule> getNoticeCache() {
|
||||
return (List<NoticeRule>) COMMON_CACHE.get(CommonConstants.CACHE_NOTICE_RULE);
|
||||
}
|
||||
|
||||
/**
|
||||
* set notice cache
|
||||
* @param noticeRules notice rules
|
||||
*/
|
||||
public static void setNoticeCache(List<NoticeRule> noticeRules) {
|
||||
COMMON_CACHE.put(CommonConstants.CACHE_NOTICE_RULE, noticeRules);
|
||||
}
|
||||
|
||||
/**
|
||||
* clear notice cache
|
||||
*/
|
||||
public static void clearNoticeCache() {
|
||||
COMMON_CACHE.remove(CommonConstants.CACHE_NOTICE_RULE);
|
||||
}
|
||||
|
||||
/**
|
||||
* get alert silence cache
|
||||
* @return caffeine cache
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static List<AlertSilence> getAlertSilenceCache() {
|
||||
return (List<AlertSilence>) COMMON_CACHE.get(CommonConstants.CACHE_ALERT_SILENCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* set alert silence cache
|
||||
* @param alertSilences alert silences
|
||||
*/
|
||||
public static void setAlertSilenceCache(List<AlertSilence> alertSilences) {
|
||||
COMMON_CACHE.put(CommonConstants.CACHE_ALERT_SILENCE, alertSilences);
|
||||
}
|
||||
|
||||
/**
|
||||
* clear alert silence cache
|
||||
*/
|
||||
public static void clearAlertSilenceCache() {
|
||||
COMMON_CACHE.remove(CommonConstants.CACHE_ALERT_SILENCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* get metrics alert define cache
|
||||
* @return caffeine cache
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static List<AlertDefine> getMetricsAlertDefineCache() {
|
||||
return (List<AlertDefine>) COMMON_CACHE.get(CommonConstants.METRIC_CACHE_ALERT_DEFINE);
|
||||
}
|
||||
|
||||
/**
|
||||
* set metrics alert define cache
|
||||
* @param alertDefines alert defines
|
||||
*/
|
||||
public static void setMetricsAlertDefineCache(List<AlertDefine> alertDefines) {
|
||||
COMMON_CACHE.put(CommonConstants.METRIC_CACHE_ALERT_DEFINE, alertDefines);
|
||||
}
|
||||
|
||||
/**
|
||||
* clear metrics alert define cache
|
||||
*/
|
||||
public static void clearMetricsAlertDefineCache() {
|
||||
COMMON_CACHE.remove(CommonConstants.METRIC_CACHE_ALERT_DEFINE);
|
||||
}
|
||||
|
||||
/**
|
||||
* get log alert define cache
|
||||
* @return caffeine cache
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static List<AlertDefine> getLogAlertDefineCache() {
|
||||
return (List<AlertDefine>) COMMON_CACHE.get(CommonConstants.LOG_CACHE_ALERT_DEFINE);
|
||||
}
|
||||
|
||||
/**
|
||||
* set log alert define cache
|
||||
* @param alertDefines alert defines
|
||||
*/
|
||||
public static void setLogAlertDefineCache(List<AlertDefine> alertDefines) {
|
||||
COMMON_CACHE.put(CommonConstants.LOG_CACHE_ALERT_DEFINE, alertDefines);
|
||||
}
|
||||
|
||||
/**
|
||||
* clear log alert define cache
|
||||
*/
|
||||
public static void clearLogAlertDefineCache() {
|
||||
COMMON_CACHE.remove(CommonConstants.LOG_CACHE_ALERT_DEFINE);
|
||||
}
|
||||
|
||||
/**
|
||||
* clear alert define cache
|
||||
*/
|
||||
public static void clearAlertDefineCache() {
|
||||
clearLogAlertDefineCache();
|
||||
clearMetricsAlertDefineCache();
|
||||
}
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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.cache;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import java.time.Duration;
|
||||
|
||||
/**
|
||||
* caffeine cache impl
|
||||
*/
|
||||
public class CaffeineCacheServiceImpl<K, V> implements CommonCacheService<K, V> {
|
||||
private final Cache<K, V> cache;
|
||||
|
||||
public CaffeineCacheServiceImpl(final int initialCapacity, final long maximumSize, final Duration expireAfterWrite, final boolean useWeakKey) {
|
||||
if (useWeakKey) {
|
||||
this.cache = Caffeine.newBuilder()
|
||||
.weakKeys()
|
||||
.initialCapacity(initialCapacity)
|
||||
.maximumSize(maximumSize)
|
||||
.expireAfterWrite(expireAfterWrite)
|
||||
.build();
|
||||
} else {
|
||||
this.cache = Caffeine.newBuilder()
|
||||
.initialCapacity(initialCapacity)
|
||||
.maximumSize(maximumSize)
|
||||
.expireAfterWrite(expireAfterWrite)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(K key) {
|
||||
return cache.getIfPresent(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, V value) {
|
||||
cache.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V putAndGetOld(K key, V value) {
|
||||
V oldValue = cache.getIfPresent(key);
|
||||
cache.put(key, value);
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(K key) {
|
||||
return cache.asMap().containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(K key) {
|
||||
V value = cache.getIfPresent(key);
|
||||
this.cache.invalidate(key);
|
||||
this.cache.cleanUp();
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean clear() {
|
||||
this.cache.invalidateAll();
|
||||
this.cache.cleanUp();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.config;
|
||||
|
||||
import org.apache.hertzbeat.common.constants.ConfigConstants;
|
||||
import org.apache.hertzbeat.common.constants.SignConstants;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
/**
|
||||
* common module config
|
||||
*/
|
||||
|
||||
@AutoConfiguration
|
||||
@ComponentScan(basePackages = ConfigConstants.PkgConstant.PKG
|
||||
+ SignConstants.DOT
|
||||
+ ConfigConstants.FunctionModuleConstants.COMMON)
|
||||
@EnableConfigurationProperties({CommonProperties.class, VirtualThreadPropertiesBinding.class, SmsConfigBinding.class})
|
||||
public class CommonConfig {
|
||||
|
||||
@Bean
|
||||
public VirtualThreadProperties virtualThreadProperties(VirtualThreadPropertiesBinding binding) {
|
||||
return binding.toRuntimeProperties();
|
||||
}
|
||||
}
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* 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.config;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.apache.hertzbeat.common.constants.ConfigConstants;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* common module properties
|
||||
*/
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ConfigurationProperties(prefix =
|
||||
ConfigConstants.FunctionModuleConstants.COMMON)
|
||||
public class CommonProperties {
|
||||
|
||||
/**
|
||||
* secret key for password aes entry, must 16 bits
|
||||
*/
|
||||
private String secret;
|
||||
|
||||
/**
|
||||
* data queue impl
|
||||
*/
|
||||
private DataQueueProperties queue;
|
||||
|
||||
/**
|
||||
* data queue properties
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public static class DataQueueProperties {
|
||||
|
||||
private QueueType type = QueueType.Memory;
|
||||
|
||||
private KafkaProperties kafka;
|
||||
|
||||
private RedisProperties redis;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* data queue type
|
||||
*/
|
||||
public enum QueueType {
|
||||
/** in memory **/
|
||||
Memory,
|
||||
/** kafka **/
|
||||
Kafka,
|
||||
/** with netty connect **/
|
||||
Netty,
|
||||
/** rabbit mq **/
|
||||
Rabbit_Mq,
|
||||
/** redis **/
|
||||
Redis
|
||||
}
|
||||
|
||||
/**
|
||||
* redis data queue properties
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public static class RedisProperties {
|
||||
|
||||
/**
|
||||
* redis server host.
|
||||
*/
|
||||
private String redisHost;
|
||||
|
||||
/**
|
||||
* redis server port.
|
||||
*/
|
||||
private int redisPort;
|
||||
|
||||
/**
|
||||
* Queue name for metrics data to alerter
|
||||
*/
|
||||
private String metricsDataQueueNameToAlerter;
|
||||
|
||||
/**
|
||||
* Queue name for metrics data to persistent storage
|
||||
*/
|
||||
private String metricsDataQueueNameToPersistentStorage;
|
||||
|
||||
/**
|
||||
* Queue name for metrics data to real-time storage
|
||||
*/
|
||||
private String metricsDataQueueNameToRealTimeStorage;
|
||||
|
||||
/**
|
||||
* Queue name for service discovery
|
||||
*/
|
||||
private String metricsDataQueueNameForServiceDiscovery;
|
||||
|
||||
/**
|
||||
* Queue name for alerts data
|
||||
*/
|
||||
private String alertsDataQueueName;
|
||||
|
||||
/**
|
||||
* Queue name for log entry data
|
||||
*/
|
||||
private String logEntryQueueName;
|
||||
|
||||
/**
|
||||
* Queue name for log entry data to storage
|
||||
*/
|
||||
private String logEntryToStorageQueueName;
|
||||
|
||||
/**
|
||||
* Timeout for blocking wait in seconds (defaults to 1 second if not configured)
|
||||
*/
|
||||
private Long waitTimeout;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* kafka data queue properties
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public static class KafkaProperties extends BaseKafkaProperties {
|
||||
|
||||
/**
|
||||
* metrics data topic
|
||||
*/
|
||||
private String metricsDataTopic;
|
||||
/**
|
||||
* metrics data to storage topic
|
||||
*/
|
||||
private String metricsDataToStorageTopic;
|
||||
/**
|
||||
* service discovery data topic
|
||||
*/
|
||||
private String serviceDiscoveryDataTopic;
|
||||
/**
|
||||
* alerts data topic
|
||||
*/
|
||||
private String alertsDataTopic;
|
||||
/**
|
||||
* log entry data topic
|
||||
*/
|
||||
private String logEntryDataTopic;
|
||||
/**
|
||||
* log entry data to storage topic
|
||||
*/
|
||||
private String logEntryDataToStorageTopic;
|
||||
}
|
||||
}
|
||||
+28
@@ -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.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.common.config;
|
||||
|
||||
import org.apache.hertzbeat.common.entity.dto.sms.SmsConfig;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Spring Boot binding adapter for {@link SmsConfig}.
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "alerter.sms")
|
||||
public class SmsConfigBinding extends SmsConfig {
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* 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.config;
|
||||
|
||||
import org.apache.hertzbeat.common.concurrent.AdmissionMode;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.bind.ConstructorBinding;
|
||||
import org.springframework.boot.context.properties.bind.DefaultValue;
|
||||
import org.springframework.boot.context.properties.bind.Name;
|
||||
|
||||
/**
|
||||
* Spring Boot binding adapter for {@link VirtualThreadProperties}.
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "hertzbeat.vthreads")
|
||||
public record VirtualThreadPropertiesBinding(
|
||||
@DefaultValue("true") boolean enabled,
|
||||
PoolProperties collector,
|
||||
PoolProperties common,
|
||||
PoolProperties manager,
|
||||
AlerterProperties alerter,
|
||||
PoolProperties warehouse,
|
||||
AsyncProperties async) {
|
||||
|
||||
@ConstructorBinding
|
||||
public VirtualThreadPropertiesBinding {
|
||||
VirtualThreadProperties runtimeProperties = new VirtualThreadProperties(enabled,
|
||||
toRuntimePool(collector),
|
||||
toRuntimePool(common),
|
||||
toRuntimePool(manager),
|
||||
toRuntimeAlerter(alerter),
|
||||
toRuntimePool(warehouse),
|
||||
toRuntimeAsync(async));
|
||||
enabled = runtimeProperties.enabled();
|
||||
collector = PoolProperties.fromRuntime(runtimeProperties.collector());
|
||||
common = PoolProperties.fromRuntime(runtimeProperties.common());
|
||||
manager = PoolProperties.fromRuntime(runtimeProperties.manager());
|
||||
alerter = AlerterProperties.fromRuntime(runtimeProperties.alerter());
|
||||
warehouse = PoolProperties.fromRuntime(runtimeProperties.warehouse());
|
||||
async = AsyncProperties.fromRuntime(runtimeProperties.async());
|
||||
}
|
||||
|
||||
public VirtualThreadProperties toRuntimeProperties() {
|
||||
return new VirtualThreadProperties(enabled,
|
||||
toRuntimePool(collector),
|
||||
toRuntimePool(common),
|
||||
toRuntimePool(manager),
|
||||
toRuntimeAlerter(alerter),
|
||||
toRuntimePool(warehouse),
|
||||
toRuntimeAsync(async));
|
||||
}
|
||||
|
||||
/**
|
||||
* Pool-level binding model.
|
||||
*/
|
||||
public record PoolProperties(
|
||||
@DefaultValue("UNBOUNDED_VT") AdmissionMode mode,
|
||||
@DefaultValue("0") int maxConcurrentJobs) {
|
||||
|
||||
@ConstructorBinding
|
||||
public PoolProperties {
|
||||
mode = mode == null ? AdmissionMode.UNBOUNDED_VT : mode;
|
||||
}
|
||||
|
||||
static PoolProperties fromRuntime(VirtualThreadProperties.PoolProperties runtimeProperties) {
|
||||
return runtimeProperties == null ? null
|
||||
: new PoolProperties(runtimeProperties.mode(), runtimeProperties.maxConcurrentJobs());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alerter-specific binding model.
|
||||
*/
|
||||
public record AlerterProperties(
|
||||
@Name("notify") PoolProperties notifyPool,
|
||||
@DefaultValue("10") int periodicMaxConcurrentJobs,
|
||||
QueueProperties logWorker,
|
||||
QueueProperties reduce,
|
||||
QueueProperties windowEvaluator,
|
||||
@DefaultValue("4") int notifyMaxConcurrentPerChannel) {
|
||||
|
||||
@ConstructorBinding
|
||||
public AlerterProperties {
|
||||
}
|
||||
|
||||
static AlerterProperties fromRuntime(VirtualThreadProperties.AlerterProperties runtimeProperties) {
|
||||
return runtimeProperties == null ? null
|
||||
: new AlerterProperties(
|
||||
PoolProperties.fromRuntime(runtimeProperties.notifyPool()),
|
||||
runtimeProperties.periodicMaxConcurrentJobs(),
|
||||
QueueProperties.fromRuntime(runtimeProperties.logWorker()),
|
||||
QueueProperties.fromRuntime(runtimeProperties.reduce()),
|
||||
QueueProperties.fromRuntime(runtimeProperties.windowEvaluator()),
|
||||
runtimeProperties.notifyMaxConcurrentPerChannel());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue-preserving binding model.
|
||||
*/
|
||||
public record QueueProperties(
|
||||
@DefaultValue("0") int maxConcurrentJobs,
|
||||
@DefaultValue("0") int queueCapacity) {
|
||||
|
||||
@ConstructorBinding
|
||||
public QueueProperties {
|
||||
}
|
||||
|
||||
static QueueProperties fromRuntime(VirtualThreadProperties.QueueProperties runtimeProperties) {
|
||||
return runtimeProperties == null ? null
|
||||
: new QueueProperties(runtimeProperties.maxConcurrentJobs(), runtimeProperties.queueCapacity());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Async executor binding model.
|
||||
*/
|
||||
public record AsyncProperties(
|
||||
@DefaultValue("true") boolean enabled,
|
||||
@DefaultValue("256") int concurrencyLimit,
|
||||
@DefaultValue("true") boolean rejectWhenLimitReached,
|
||||
@DefaultValue("5000") long taskTerminationTimeout) {
|
||||
|
||||
@ConstructorBinding
|
||||
public AsyncProperties {
|
||||
}
|
||||
|
||||
static AsyncProperties fromRuntime(VirtualThreadProperties.AsyncProperties runtimeProperties) {
|
||||
return runtimeProperties == null ? null
|
||||
: new AsyncProperties(runtimeProperties.enabled(), runtimeProperties.concurrencyLimit(),
|
||||
runtimeProperties.rejectWhenLimitReached(), runtimeProperties.taskTerminationTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
private static VirtualThreadProperties.PoolProperties toRuntimePool(PoolProperties poolProperties) {
|
||||
return poolProperties == null ? null
|
||||
: new VirtualThreadProperties.PoolProperties(poolProperties.mode(), poolProperties.maxConcurrentJobs());
|
||||
}
|
||||
|
||||
private static VirtualThreadProperties.AlerterProperties toRuntimeAlerter(AlerterProperties alerterProperties) {
|
||||
return alerterProperties == null ? null
|
||||
: new VirtualThreadProperties.AlerterProperties(
|
||||
toRuntimePool(alerterProperties.notifyPool()),
|
||||
alerterProperties.periodicMaxConcurrentJobs(),
|
||||
toRuntimeQueue(alerterProperties.logWorker()),
|
||||
toRuntimeQueue(alerterProperties.reduce()),
|
||||
toRuntimeQueue(alerterProperties.windowEvaluator()),
|
||||
alerterProperties.notifyMaxConcurrentPerChannel());
|
||||
}
|
||||
|
||||
private static VirtualThreadProperties.QueueProperties toRuntimeQueue(QueueProperties queueProperties) {
|
||||
return queueProperties == null ? null
|
||||
: new VirtualThreadProperties.QueueProperties(queueProperties.maxConcurrentJobs(),
|
||||
queueProperties.queueCapacity());
|
||||
}
|
||||
|
||||
private static VirtualThreadProperties.AsyncProperties toRuntimeAsync(AsyncProperties asyncProperties) {
|
||||
return asyncProperties == null ? null
|
||||
: new VirtualThreadProperties.AsyncProperties(asyncProperties.enabled(),
|
||||
asyncProperties.concurrencyLimit(), asyncProperties.rejectWhenLimitReached(),
|
||||
asyncProperties.taskTerminationTimeout());
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.ai;
|
||||
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
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;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Entity for storing AI chat conversation metadata
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@Entity
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
@Table(name = "hzb_ai_conversation")
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ChatConversation {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "conversation title")
|
||||
private String title;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom", accessMode = READ_ONLY)
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "The modifier of this record", example = "tom", accessMode = READ_ONLY)
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "Record create time", example = "1612198922000", accessMode = READ_ONLY)
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record modify time", example = "1612198444000", accessMode = READ_ONLY)
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
|
||||
/**
|
||||
* List of messages in this conversation (one-to-many relationship)
|
||||
*/
|
||||
@OneToMany(mappedBy = "conversation")
|
||||
private List<ChatMessage> messages;
|
||||
|
||||
private String securityData;
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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.ai;
|
||||
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.Lob;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import java.time.LocalDateTime;
|
||||
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;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Entity for storing individual chat messages in conversations
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@Entity
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
@Table(name = "hzb_ai_message", indexes = {
|
||||
@Index(name = "idx_message_conversation_id", columnList = "conversation_id")
|
||||
})
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ChatMessage {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "conversation id")
|
||||
@Column(name = "conversation_id", insertable = false, updatable = false)
|
||||
private Long conversationId;
|
||||
|
||||
@Schema(title = "conversation", hidden = true)
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "conversation_id")
|
||||
private ChatConversation conversation;
|
||||
|
||||
@Schema(title = "message content")
|
||||
@Lob
|
||||
@NotBlank
|
||||
private String content;
|
||||
|
||||
@Schema(title = "message role: user, system")
|
||||
private String role;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom", accessMode = READ_ONLY)
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "The modifier of this record", example = "tom", accessMode = READ_ONLY)
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "Record create time", example = "1612198922000", accessMode = READ_ONLY)
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record modify time", example = "1612198444000", accessMode = READ_ONLY)
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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.ai;
|
||||
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Entity for storing scheduled SOP execution configurations.
|
||||
* Allows users to schedule automatic SOP executions with results pushed to conversations.
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@Entity
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
@Table(name = "hzb_sop_schedule", indexes = {
|
||||
@Index(name = "idx_schedule_conversation_id", columnList = "conversation_id"),
|
||||
@Index(name = "idx_schedule_enabled_next", columnList = "enabled, next_run_time")
|
||||
})
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class SopSchedule {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "Conversation ID to push results to")
|
||||
@NotNull
|
||||
@Column(name = "conversation_id")
|
||||
private Long conversationId;
|
||||
|
||||
@Schema(title = "Name of the SOP skill to execute")
|
||||
@NotBlank
|
||||
@Column(name = "sop_name", length = 64)
|
||||
private String sopName;
|
||||
|
||||
@Schema(title = "SOP execution parameters in JSON format")
|
||||
@Column(name = "sop_params", length = 1024)
|
||||
private String sopParams;
|
||||
|
||||
@Schema(title = "Cron expression for scheduling")
|
||||
@NotBlank
|
||||
@Column(name = "cron_expression", length = 64)
|
||||
private String cronExpression;
|
||||
|
||||
@Schema(title = "Whether the schedule is enabled")
|
||||
@Builder.Default
|
||||
@Column(name = "enabled")
|
||||
private Boolean enabled = true;
|
||||
|
||||
@Schema(title = "Last execution time")
|
||||
@Column(name = "last_run_time")
|
||||
private LocalDateTime lastRunTime;
|
||||
|
||||
@Schema(title = "Next scheduled execution time")
|
||||
@Column(name = "next_run_time")
|
||||
private LocalDateTime nextRunTime;
|
||||
|
||||
@Schema(title = "The creator of this record", accessMode = READ_ONLY)
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "The modifier of this record", accessMode = READ_ONLY)
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "Record create time", accessMode = READ_ONLY)
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record modify time", accessMode = READ_ONLY)
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
}
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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.alerter;
|
||||
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY;
|
||||
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.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Alarm Define Rule Entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_alert_define")
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Alarm Threshold Entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class AlertDefine {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "Threshold Id", example = "87584674384", accessMode = READ_ONLY)
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "Alert Rule Name", example = "high_cpu_usage", accessMode = READ_WRITE)
|
||||
@Size(max = 100)
|
||||
@NotNull
|
||||
private String name;
|
||||
|
||||
@Schema(title = "Rule Type: realtime_metric, periodic_metric, realtime_log, periodic_log", example = "realtime_metric")
|
||||
private String type;
|
||||
|
||||
@Schema(title = "Alarm Threshold Expr", example = "usage>90", accessMode = READ_WRITE)
|
||||
@Size(max = 2048)
|
||||
@Column(length = 2048)
|
||||
private String expr;
|
||||
|
||||
@Schema(title = "Execution Period/ Window Size (seconds) - For periodic rules/ For log realtime", example = "300")
|
||||
private Integer period;
|
||||
|
||||
@Schema(title = "Alarm Trigger Times.The alarm is triggered only after the required number of times is reached",
|
||||
example = "3", accessMode = READ_WRITE)
|
||||
private Integer times;
|
||||
|
||||
@Schema(description = "labels(status:success,env:prod,priority:critical)", example = "{name: key1, value: value1}",
|
||||
accessMode = READ_WRITE)
|
||||
@Convert(converter = JsonMapAttributeConverter.class)
|
||||
@Column(length = 2048)
|
||||
private Map<String, String> labels;
|
||||
|
||||
@Schema(title = "Annotations", example = "summary: High CPU usage")
|
||||
@Convert(converter = JsonMapAttributeConverter.class)
|
||||
@Column(length = 4096)
|
||||
private Map<String, String> annotations;
|
||||
|
||||
@Schema(title = "Alert Content Template", example = "Instance {{ $labels.instance }} CPU usage is {{ $value }}%")
|
||||
@Size(max = 2048)
|
||||
@Column(length = 2048)
|
||||
private String template;
|
||||
|
||||
@Schema(title = "Data Source Type", example = "PROMETHEUS")
|
||||
@Size(max = 100)
|
||||
private String datasource;
|
||||
|
||||
@Schema(title = "Is Enabled", example = "true")
|
||||
private boolean enable = true;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom", accessMode = READ_ONLY)
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "The modifier of this record", example = "tom", accessMode = READ_ONLY)
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "Record create time", example = "1612198922000", accessMode = READ_ONLY)
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record modify time", example = "1612198444000", accessMode = READ_ONLY)
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.alerter;
|
||||
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY;
|
||||
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.ConstraintMode;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.ForeignKey;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.hertzbeat.common.entity.manager.Monitor;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
/**
|
||||
* Alarm Threshold Relate Monitor Entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_alert_define_monitor_bind", indexes = {
|
||||
@Index(name = "idx_alert_define_id", columnList = "alert_define_id"),
|
||||
@Index(name = "idx_monitor_id", columnList = "monitor_id")
|
||||
})
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Alarm Threshold Relate Monitor Entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class AlertDefineMonitorBind {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "id", example = "74384", accessMode = READ_ONLY)
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "Alarm Define Id", example = "87432674384", accessMode = READ_WRITE)
|
||||
private Long alertDefineId;
|
||||
|
||||
@Schema(title = "Monitor Id", example = "87432674336", accessMode = READ_WRITE)
|
||||
@Column(name = "monitor_id")
|
||||
private Long monitorId;
|
||||
|
||||
@Schema(title = "Record create time", example = "1612198922000", accessMode = READ_ONLY)
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record modify time", example = "1612198444000", accessMode = READ_ONLY)
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
|
||||
@OneToOne(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "monitor_id", referencedColumnName = "id", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT),
|
||||
insertable = false, updatable = false)
|
||||
// todo instead of @NotFound
|
||||
// @NotFound(action = NotFoundAction.IGNORE)
|
||||
private Monitor monitor;
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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.alerter;
|
||||
|
||||
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.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
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.JsonStringListAttributeConverter;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Alert group converge strategy entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_alert_group_converge", indexes = {
|
||||
@Index(name = "idx_name", columnList = "name")
|
||||
})
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Alert Group Converge Policy Entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class AlertGroupConverge {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "Primary Key Index ID", example = "87584674384")
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "Policy name", example = "group-converge-1")
|
||||
@Size(max = 100)
|
||||
@NotNull
|
||||
@Column(name = "name")
|
||||
private String name;
|
||||
|
||||
@Schema(title = "Labels to group by", example = "[\"instance\"]")
|
||||
@Convert(converter = JsonStringListAttributeConverter.class)
|
||||
@Column(name = "group_labels", length = 1024)
|
||||
private List<String> groupLabels;
|
||||
|
||||
@Schema(title = "Initial wait time before sending first group alert (s)", example = "30")
|
||||
@Column(name = "group_wait")
|
||||
private Long groupWait;
|
||||
|
||||
@Schema(title = "Interval between group alert sends (s)", example = "300")
|
||||
@Column(name = "group_interval")
|
||||
private Long groupInterval;
|
||||
|
||||
@Schema(title = "Interval for repeating firing alerts (s), set to 0 to disable repeating", example = "9000")
|
||||
@Column(name = "repeat_interval")
|
||||
private Long repeatInterval;
|
||||
|
||||
@Schema(title = "Whether to enable this policy", example = "true")
|
||||
private Boolean enable;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom")
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "This record was last modified by", example = "tom")
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "This record creation time (millisecond timestamp)")
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record the latest modification time (timestamp in milliseconds)")
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
}
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.alerter;
|
||||
|
||||
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.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.hertzbeat.common.entity.manager.JsonStringListAttributeConverter;
|
||||
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;
|
||||
|
||||
/**
|
||||
* alert inhibit rule
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_alert_inhibit")
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Alert Inhibit Rule Entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class AlertInhibit {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "Inhibit Rule ID", example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "Inhibit Rule Name", example = "inhibit_high_cpu")
|
||||
@Size(max = 100)
|
||||
@NotNull
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Source alert labels that must match for the inhibit rule to be active
|
||||
* Example: severity=critical,instance=web-01
|
||||
*/
|
||||
@Schema(title = "Source Alert Match Labels")
|
||||
@Convert(converter = JsonMapAttributeConverter.class)
|
||||
@Column(length = 2048)
|
||||
private Map<String, String> sourceLabels;
|
||||
|
||||
/**
|
||||
* Target alert labels that must match to be inhibited
|
||||
* Example: severity=warning,instance=web-01
|
||||
*/
|
||||
@Schema(title = "Target Alert Match Labels")
|
||||
@Convert(converter = JsonMapAttributeConverter.class)
|
||||
@Column(length = 2048)
|
||||
private Map<String, String> targetLabels;
|
||||
|
||||
/**
|
||||
* Labels that must have the same value in the source and target alert for the inhibit rule to be active
|
||||
* Example: ["instance", "job"]
|
||||
*/
|
||||
@Schema(title = "Equal Labels")
|
||||
@Convert(converter = JsonStringListAttributeConverter.class)
|
||||
@Column(length = 2048)
|
||||
private List<String> equalLabels;
|
||||
|
||||
@Schema(title = "Whether to enable this policy", example = "true")
|
||||
private Boolean enable;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom")
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "This record was last modified by", example = "tom")
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "This record creation time (millisecond timestamp)")
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record the latest modification time (timestamp in milliseconds)")
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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.alerter;
|
||||
|
||||
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.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.hertzbeat.common.entity.manager.JsonByteListAttributeConverter;
|
||||
import org.apache.hertzbeat.common.entity.manager.ZonedDateTimeAttributeConverter;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Alert Silence strategy entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_alert_silence")
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Alert Silence Policy Entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class AlertSilence {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "Primary Key Index ID",
|
||||
example = "87584674384")
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "Policy name", example = "silence-1")
|
||||
@Size(max = 100)
|
||||
@NotNull
|
||||
private String name;
|
||||
|
||||
@Schema(title = "Whether to enable this policy", example = "true")
|
||||
private boolean enable = true;
|
||||
|
||||
@Schema(title = "Whether to match all", example = "true")
|
||||
private boolean matchAll = true;
|
||||
|
||||
@Schema(title = "Silence type 0: once, 1:cyc", example = "1")
|
||||
@NotNull
|
||||
private Byte type;
|
||||
|
||||
@Schema(title = "Silenced alerts num", example = "3")
|
||||
private Integer times;
|
||||
|
||||
@Schema(description = "Match the alarm information label", example = "{name: key1, value: value1}")
|
||||
@Convert(converter = JsonMapAttributeConverter.class)
|
||||
@Column(length = 2048)
|
||||
private Map<String, String> labels;
|
||||
|
||||
@Schema(title = "The day of the WEEK is valid in periodic silence, multiple,"
|
||||
+ " all or empty is daily 7: Sunday 1: Monday 2: Tuesday 3: Wednesday 4: Thursday 5: Friday 6: Saturday",
|
||||
example = "[0,1]")
|
||||
@Convert(converter = JsonByteListAttributeConverter.class)
|
||||
private List<Byte> days;
|
||||
|
||||
@Schema(title = "Limit time period start", example = "00:00:00")
|
||||
@Convert(converter = ZonedDateTimeAttributeConverter.class)
|
||||
private ZonedDateTime periodStart;
|
||||
|
||||
@Schema(title = "Restricted time period end", example = "23:59:59")
|
||||
@Convert(converter = ZonedDateTimeAttributeConverter.class)
|
||||
private ZonedDateTime periodEnd;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom")
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "This record was last modified by", example = "tom")
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "This record creation time (millisecond timestamp)")
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record the latest modification time (timestamp in milliseconds)")
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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.alerter;
|
||||
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
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.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.Transient;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.hertzbeat.common.entity.manager.JsonStringListAttributeConverter;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Group Alert Content Entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_alert_group", indexes = {@Index(name = "unique_group_key", columnList = "group_key", unique = true)})
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Group Alarm Content Entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class GroupAlert {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "Threshold Id", example = "87584674384", accessMode = READ_ONLY)
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "Group Key", example = "HighCPUUsage{alertname=\"HighCPUUsage\", instance=\"server1\"}")
|
||||
@Column(length = 2048)
|
||||
private String groupKey;
|
||||
|
||||
@Schema(title = "Status", example = "resolved")
|
||||
private String status;
|
||||
|
||||
@Schema(title = "Group Labels", example = "{\"alertname\": \"HighCPUUsage\"}")
|
||||
@Convert(converter = JsonMapAttributeConverter.class)
|
||||
@Column(length = 2048)
|
||||
private Map<String, String> groupLabels;
|
||||
|
||||
@Schema(title = "Common Labels", example = "{\"alertname\": \"HighCPUUsage\", \"instance\": \"server1\", \"severity\": \"critical\"}")
|
||||
@Convert(converter = JsonMapAttributeConverter.class)
|
||||
@Column(length = 2048)
|
||||
private Map<String, String> commonLabels;
|
||||
|
||||
@Schema(title = "Common Annotations", example = "{\"summary\": \"High CPU usage detected\", \"description\": \"CPU usage is back to normal for server1\"}")
|
||||
@Convert(converter = JsonMapAttributeConverter.class)
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private Map<String, String> commonAnnotations;
|
||||
|
||||
@Schema(title = "Alert Fingerprints", example = "[\"dxsdfdsf\"]")
|
||||
@Convert(converter = JsonStringListAttributeConverter.class)
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private List<String> alertFingerprints;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom")
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "This record was last modified by", example = "tom")
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "This record creation time (millisecond timestamp)")
|
||||
@CreatedDate
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record the latest modification time (timestamp in milliseconds)")
|
||||
@LastModifiedDate
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime gmtUpdate;
|
||||
|
||||
@Transient
|
||||
private List<SingleAlert> alerts;
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.alerter;
|
||||
|
||||
import tools.jackson.core.type.TypeReference;
|
||||
import jakarta.persistence.AttributeConverter;
|
||||
import jakarta.persistence.Converter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import org.apache.hertzbeat.common.util.JsonUtil;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* json map converter
|
||||
*/
|
||||
@Converter
|
||||
@Component
|
||||
public class JsonMapAttributeConverter implements AttributeConverter<Map<String, String>, String> {
|
||||
|
||||
@Override
|
||||
public String convertToDatabaseColumn(Map<String, String> attribute) {
|
||||
return JsonUtil.toJson(attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> convertToEntityAttribute(String dbData) {
|
||||
TypeReference<Map<String, String>> typeReference = new TypeReference<>() {};
|
||||
Map<String, String> map = JsonUtil.fromJson(dbData, typeReference);
|
||||
return Objects.requireNonNullElseGet(map, HashMap::new);
|
||||
}
|
||||
}
|
||||
+301
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* 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.alerter;
|
||||
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY;
|
||||
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.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Message notification recipient entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_notice_receiver")
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Message notification recipient entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class NoticeReceiver {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "Recipient entity primary key index ID", description = "Recipient entity primary key index ID",
|
||||
example = "87584674384", accessMode = READ_ONLY)
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "Recipient name", description = "Recipient name",
|
||||
example = "tom", accessMode = READ_WRITE)
|
||||
@Size(max = 100)
|
||||
@NotBlank(message = "name can not null")
|
||||
private String name;
|
||||
|
||||
@Schema(title = "Notification information method: 0-SMS 1-Email 2-webhook 3-WeChat Official Account 4-Enterprise WeChat Robot "
|
||||
+ "5-DingTalk Robot 6-FeiShu Robot 7-Telegram Bot 8-SlackWebHook 9-Discord Bot 10-Enterprise WeChat app message "
|
||||
+ "11-Huawei Cloud SMN 12-ServerChan 13-Gotify 14-FeiShu app message 15-Ntfy",
|
||||
description = "Notification information method: "
|
||||
+ "0-SMS 1-Email 2-webhook 3-WeChat Official Account "
|
||||
+ "4-Enterprise WeChat Robot 5-DingTalk Robot 6-FeiShu Robot "
|
||||
+ "7-Telegram Bot 8-SlackWebHook 9-Discord Bot 10-Enterprise "
|
||||
+ "WeChat app message 11-Huawei Cloud SMN 12-ServerChan 13-Gotify 14-FeiShu app message 15-Ntfy",
|
||||
accessMode = READ_WRITE)
|
||||
@Min(0)
|
||||
@NotNull(message = "type can not null")
|
||||
private Byte type;
|
||||
|
||||
@Schema(title = "Mobile number: Valid when the notification method is SMS",
|
||||
description = "Mobile number: Valid when the notification method is SMS",
|
||||
example = "18923435643", accessMode = READ_WRITE)
|
||||
@Size(max = 100)
|
||||
private String phone;
|
||||
|
||||
@Schema(title = "Email account: Valid when the notification method is email",
|
||||
description = "Email account: Valid when the notification method is email",
|
||||
example = "tom@qq.com", accessMode = READ_WRITE)
|
||||
@Size(max = 100)
|
||||
private String email;
|
||||
|
||||
@Schema(title = "URL address: The notification method is valid for webhook",
|
||||
description = "URL address: The notification method is valid for webhook",
|
||||
example = "https://www.tancloud.cn", accessMode = READ_WRITE)
|
||||
@Size(max = 1000)
|
||||
@Column(length = 1000)
|
||||
private String hookUrl;
|
||||
|
||||
@Schema(title = "Auth Type: WebHook Authorization Type",
|
||||
description = "Auth Type: WebHook Authorization Type, one of the 'None', 'Basic' and 'Bearer'",
|
||||
example = "None", accessMode = READ_ONLY)
|
||||
@Size(max = 300)
|
||||
@Column(length = 300)
|
||||
private String hookAuthType;
|
||||
|
||||
@Schema(title = "Auth Token: WebHook Authorization Token",
|
||||
description = "Auth Token: WebHook Authorization Token",
|
||||
example = "YWxpY2U6c3VwZXJtYW4", accessMode = READ_WRITE)
|
||||
@Size(max = 300)
|
||||
@Column(length = 300)
|
||||
private String hookAuthToken;
|
||||
|
||||
@Schema(title = "openId : The notification method is valid for WeChat official account, enterprise WeChat robot or FlyBook robot",
|
||||
description = "openId : The notification method is valid for WeChat official account, enterprise WeChat robot or FlyBook robot",
|
||||
example = "343432", accessMode = READ_WRITE)
|
||||
@Size(max = 300)
|
||||
@Column(length = 300)
|
||||
private String wechatId;
|
||||
|
||||
@Schema(title = "FeiShu app id : The notification method is valid for FeiShu app message",
|
||||
description = "FeiShu app id : The notification method is valid for FeiShu app message",
|
||||
example = "34823984635647", accessMode = READ_WRITE)
|
||||
@Size(max = 255)
|
||||
private String appId;
|
||||
|
||||
@Schema(title = "Access token : The notification method is valid for DingTalk robot",
|
||||
description = "Access token : The notification method is valid for DingTalk robot",
|
||||
example = "34823984635647", accessMode = READ_WRITE)
|
||||
@Size(max = 300)
|
||||
@Column(length = 300)
|
||||
private String accessToken;
|
||||
|
||||
@Schema(title = "Telegram bot token : The notification method is valid for Telegram Bot",
|
||||
description = "Telegram bot token : The notification method is valid for Telegram Bot",
|
||||
example = "1499012345:AAEOB_wEYS-DZyPM3h5NzI8voJMXXXXXX", accessMode = READ_WRITE)
|
||||
private String tgBotToken;
|
||||
|
||||
@Schema(title = "Telegram user id: The notification method is valid for Telegram Bot",
|
||||
description = "Telegram user id: The notification method is valid for Telegram Bot",
|
||||
example = "779294123", accessMode = READ_WRITE)
|
||||
private String tgUserId;
|
||||
|
||||
@Schema(title = "Telegram message thread id: The notification method is valid for Telegram Bot",
|
||||
description = "TTelegram message thread id: The notification method is valid for Telegram Bot",
|
||||
example = "779294123", accessMode = READ_WRITE)
|
||||
private String tgMessageThreadId;
|
||||
|
||||
@Schema(title = "FeiShu app message receiveType: 0-user 1-chat 2-party 3-all",
|
||||
description = "FeiShu app message receiveType: 0-user 1-chat 2-party 3-all",
|
||||
example = "1", accessMode = READ_WRITE)
|
||||
private Byte larkReceiveType;
|
||||
|
||||
@Schema(title = "DingTalk,FeiShu,WeWork user id: The notification method is valid for DingTalk,FeiShu,WeWork Bot",
|
||||
description = "DingTalk,FeiShu,WeWork user id: The notification method is valid for DingTalk,FeiShu,WeWork Bot",
|
||||
example = "779294123", accessMode = READ_WRITE)
|
||||
private String userId;
|
||||
|
||||
@Schema(title = "FeiShu app message chatId: The notification method is valid for FeiShu app message",
|
||||
description = "FeiShu app message chatId: The notification method is valid for FeiShu app message",
|
||||
example = "779294123", accessMode = READ_WRITE)
|
||||
private String chatId;
|
||||
|
||||
@Schema(title = "URL address: The notification method is valid for Slack",
|
||||
description = "URL address: The notification method is valid for Slack",
|
||||
example = "https://hooks.slack.com/services/XXXX/XXXX/XXXX", accessMode = READ_WRITE)
|
||||
@Size(max = 300)
|
||||
@Column(length = 300)
|
||||
private String slackWebHookUrl;
|
||||
|
||||
@Schema(title = "Enterprise weChat message: The notification method is valid for Enterprise WeChat app message",
|
||||
description = "Enterprise weChat message: The notification method is valid for Enterprise WeChat app message",
|
||||
example = "ww1a603432123d0dc1", accessMode = READ_WRITE)
|
||||
private String corpId;
|
||||
|
||||
@Schema(title = "Enterprise weChat appId: The notification method is valid for Enterprise WeChat app message",
|
||||
description = "Enterprise weChat appId: The notification method is valid for Enterprise WeChat app message",
|
||||
example = "1000001", accessMode = READ_WRITE)
|
||||
private Integer agentId;
|
||||
|
||||
@Schema(title = "Enterprise weChat secret: The notification method is valid for Enterprise WeChat app message",
|
||||
description = "Enterprise weChat secret: The notification method is valid for Enterprise WeChat app message",
|
||||
example = "oUydwn92ey0lnuY02MixNa57eNK-20dJn5NEOG-u2uE", accessMode = READ_WRITE)
|
||||
private String appSecret;
|
||||
|
||||
@Schema(title = "Enterprise weChat party id: The notification method is valid for Enterprise WeChat app message",
|
||||
description = "Enterprise weChat party id: The notification method is valid for Enterprise WeChat app message",
|
||||
example = "779294123", accessMode = READ_WRITE)
|
||||
private String partyId;
|
||||
|
||||
@Schema(title = "Enterprise weChat tag id: The notification method is valid for Enterprise WeChat app message",
|
||||
description = "Enterprise weChat tag id: The notification method is valid for Enterprise WeChat app message",
|
||||
example = "779294123", accessMode = READ_WRITE)
|
||||
private String tagId;
|
||||
|
||||
@Schema(title = "Discord channel id: The notification method is valid for Discord",
|
||||
description = "Discord channel id: The notification method is valid for Discord",
|
||||
example = "1065303416030642266", accessMode = READ_WRITE)
|
||||
@Size(max = 300)
|
||||
@Column(length = 300)
|
||||
private String discordChannelId;
|
||||
|
||||
@Schema(title = "Discord bot token: The notification method is valid for Discord",
|
||||
description = "Discord bot token: The notification method is valid for Discord",
|
||||
example = "MTA2NTMwMzU0ODY4Mzg4MjUzNw.xxxxx.xxxxxxx", accessMode = READ_WRITE)
|
||||
@Size(max = 300)
|
||||
@Column(length = 300)
|
||||
private String discordBotToken;
|
||||
|
||||
@Schema(title = "huawei cloud SMN ak: If the notification method is valid for huawei cloud SMN",
|
||||
description = "huawei cloud SMN ak: If the notification method is valid for huawei cloud SMN",
|
||||
example = "NCVBODJOEYHSW3VNXXXX", accessMode = READ_WRITE)
|
||||
@Size(max = 22)
|
||||
@Column(length = 22)
|
||||
private String smnAk;
|
||||
|
||||
@Schema(title = "huawei cloud SMN sk: If the notification method is valid for huawei cloud SMN",
|
||||
description = "huawei cloud SMN sk: If the notification method is valid for huawei cloud SMN",
|
||||
example = "nmSNhUJN9MlpPl8lfCsgdA0KvHCL9JXXXX", accessMode = READ_WRITE)
|
||||
@Size(max = 42)
|
||||
@Column(length = 42)
|
||||
private String smnSk;
|
||||
|
||||
@Schema(title = "huawei cloud SMN projectId: If the notification method is valid for huawei cloud SMN",
|
||||
description = "huawei cloud SMN projectId: If the notification method is valid for huawei cloud SMN",
|
||||
example = "320c2fb11edb47a481c299c1XXXXXX", accessMode = READ_WRITE)
|
||||
@Size(max = 32)
|
||||
@Column(length = 32)
|
||||
private String smnProjectId;
|
||||
|
||||
@Schema(title = "huawei cloud SMN region: If the notification method is valid for huawei cloud SMN",
|
||||
description = "huawei cloud SMN region: If the notification method is valid for huawei cloud SMN",
|
||||
example = "cn-east-3", accessMode = READ_WRITE)
|
||||
@Size(max = 32)
|
||||
@Column(length = 32)
|
||||
private String smnRegion;
|
||||
|
||||
@Schema(title = "huawei cloud SMN TopicUrn: If the notification method is valid for huawei cloud SMN",
|
||||
description = "huawei cloud SMN TopicUrn: If the notification method is valid for huawei cloud SMN",
|
||||
example = "urn:smn:cn-east-3:xxx:hertzbeat_test", accessMode = READ_WRITE)
|
||||
@Size(max = 300)
|
||||
@Column(length = 300)
|
||||
private String smnTopicUrn;
|
||||
|
||||
@Schema(title = "serverChanToken : The notification method is valid for ServerChan",
|
||||
description = "serverChanToken : The notification method is valid for ServerChan",
|
||||
example = "SCT193569TSNm6xIabdjqeZPtOGOWcvU1e", accessMode = READ_WRITE)
|
||||
@Size(max = 300)
|
||||
@Column(length = 300)
|
||||
private String serverChanToken;
|
||||
|
||||
@Schema(title = "Gotify token : The notification method is valid for Gotify",
|
||||
description = "Gotify token : The notification method is valid for Gotify",
|
||||
example = "A845h__ZMqDxZlO", accessMode = READ_WRITE)
|
||||
@Size(max = 300)
|
||||
@Column(length = 300)
|
||||
private String gotifyToken;
|
||||
|
||||
@Schema(title = "Ntfy server URL : The notification method is valid for Ntfy",
|
||||
description = "Ntfy server URL : The notification method is valid for Ntfy, default is https://ntfy.sh",
|
||||
example = "https://ntfy.sh", accessMode = READ_WRITE)
|
||||
@Size(max = 300)
|
||||
@Column(length = 300)
|
||||
private String ntfyServerUrl;
|
||||
|
||||
@Schema(title = "Ntfy topic : The notification method is valid for Ntfy",
|
||||
description = "Ntfy topic : The notification method is valid for Ntfy",
|
||||
example = "hertzbeat-alerts", accessMode = READ_WRITE)
|
||||
@Size(max = 300)
|
||||
@Column(length = 300)
|
||||
private String ntfyTopic;
|
||||
|
||||
@Schema(title = "Ntfy access token : Bearer token for self-hosted ntfy servers with authentication",
|
||||
description = "Ntfy access token : Bearer token for self-hosted ntfy servers with authentication",
|
||||
example = "tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2", accessMode = READ_WRITE)
|
||||
@Size(max = 300)
|
||||
@Column(length = 300)
|
||||
private String ntfyToken;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom",
|
||||
accessMode = READ_ONLY)
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "This record was last modified by", example = "tom", accessMode = READ_ONLY)
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "Record creation time (millisecond timestamp)",
|
||||
example = "1612198922000", accessMode = READ_ONLY)
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record the latest modification time (timestamp in milliseconds)",
|
||||
example = "1612198444000", accessMode = READ_ONLY)
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
|
||||
}
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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.alerter;
|
||||
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY;
|
||||
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.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.hertzbeat.common.entity.manager.JsonByteListAttributeConverter;
|
||||
import org.apache.hertzbeat.common.entity.manager.JsonLongListAttributeConverter;
|
||||
import org.apache.hertzbeat.common.entity.manager.JsonStringListAttributeConverter;
|
||||
import org.apache.hertzbeat.common.entity.manager.ZonedDateTimeAttributeConverter;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Notification strategy entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_notice_rule")
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Notify Policy Entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class NoticeRule {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "Notification Policy Entity Primary Key Index ID",
|
||||
description = "Notification Policy Entity Primary Key Index ID",
|
||||
example = "87584674384", accessMode = READ_ONLY)
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "Policy name",
|
||||
description = "Policy name",
|
||||
example = "dispatch-1", accessMode = READ_WRITE)
|
||||
@Size(max = 100)
|
||||
@NotBlank(message = "name can not null")
|
||||
private String name;
|
||||
|
||||
@Schema(title = "Recipient ID",
|
||||
description = "Recipient ID",
|
||||
example = "4324324", accessMode = READ_WRITE)
|
||||
@NotEmpty(message = "receiverId can not empty")
|
||||
@Convert(converter = JsonLongListAttributeConverter.class)
|
||||
private List<Long> receiverId;
|
||||
|
||||
@Schema(title = "Recipient identification",
|
||||
description = "Recipient identification",
|
||||
example = "tom", accessMode = READ_WRITE)
|
||||
@Convert(converter = JsonStringListAttributeConverter.class)
|
||||
private List<String> receiverName;
|
||||
|
||||
@Schema(title = "Template ID",
|
||||
description = "Template ID",
|
||||
example = "4324324", accessMode = READ_WRITE)
|
||||
private Long templateId;
|
||||
|
||||
@Schema(title = "Template identification",
|
||||
description = "Template identification",
|
||||
example = "demo", accessMode = READ_WRITE)
|
||||
@Size(max = 100)
|
||||
private String templateName;
|
||||
|
||||
@Schema(title = "Whether to enable this policy",
|
||||
description = "Whether to enable this policy",
|
||||
example = "true", accessMode = READ_WRITE)
|
||||
private boolean enable = true;
|
||||
|
||||
@Schema(title = "Whether to forward all",
|
||||
description = "Whether to forward all",
|
||||
example = "false", accessMode = READ_WRITE)
|
||||
private boolean filterAll = true;
|
||||
|
||||
@Schema(title = "Labels", example = "{\"alertname\": \"HighCPUUsage\", \"priority\": \"critical\", \"instance\": \"343483943\"}")
|
||||
@Convert(converter = JsonMapAttributeConverter.class)
|
||||
@Column(length = 2048)
|
||||
private Map<String, String> labels;
|
||||
|
||||
@Schema(title = "Day of the week, multiple, all or empty is daily 7: Sunday 1: Monday 2: Tuesday 3: Wednesday 4: Thursday 5: Friday 6: Saturday",
|
||||
example = "[0,1]", accessMode = READ_WRITE)
|
||||
@Convert(converter = JsonByteListAttributeConverter.class)
|
||||
private List<Byte> days;
|
||||
|
||||
@Schema(title = "Limit time period start", example = "00:00:00", accessMode = READ_WRITE)
|
||||
@Convert(converter = ZonedDateTimeAttributeConverter.class)
|
||||
private ZonedDateTime periodStart;
|
||||
|
||||
@Schema(title = "Restricted time period end", example = "23:59:59", accessMode = READ_WRITE)
|
||||
@Convert(converter = ZonedDateTimeAttributeConverter.class)
|
||||
private ZonedDateTime periodEnd;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom", accessMode = READ_ONLY)
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "This record was last modified by", example = "tom", accessMode = READ_ONLY)
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "This record creation time (millisecond timestamp)", accessMode = READ_ONLY)
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record the latest modification time (timestamp in milliseconds)", accessMode = READ_ONLY)
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
}
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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.alerter;
|
||||
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY;
|
||||
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.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Lob;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Notification template entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_notice_template")
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Notify Policy Template")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class NoticeTemplate {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "Notification Template Entity Primary Key Index ID",
|
||||
description = "Notification Template Entity Primary Key Index ID",
|
||||
example = "87584674384", accessMode = READ_ONLY)
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "Template name",
|
||||
description = "Template name",
|
||||
example = "dispatch-1", accessMode = READ_WRITE)
|
||||
@Size(max = 100)
|
||||
@NotBlank
|
||||
private String name;
|
||||
|
||||
@Schema(title = "Notification information method: 0-SMS 1-Email 2-webhook 3-WeChat Official Account 4-Enterprise WeChat Robot "
|
||||
+ "5-DingTalk Robot 6-FeiShu Robot 7-Telegram Bot 8-SlackWebHook 9-Discord Bot 10-Enterprise WeChat app message",
|
||||
description = "Notification information method: "
|
||||
+ "0-SMS 1-Email 2-webhook 3-WeChat Official Account "
|
||||
+ "4-Enterprise WeChat Robot 5-DingTalk Robot 6-FeiShu Robot "
|
||||
+ "7-Telegram Bot 8-SlackWebHook 9-Discord Bot 10-Enterprise WeChat app message",
|
||||
accessMode = READ_WRITE)
|
||||
@Min(0)
|
||||
@NotNull
|
||||
private Byte type;
|
||||
|
||||
@Schema(title = "Is it a preset template: true- preset template false- custom template.",
|
||||
description = "Is it a preset template: true- preset template false- custom template.",
|
||||
accessMode = READ_WRITE)
|
||||
@Column(columnDefinition = "boolean default false")
|
||||
private boolean preset = false;
|
||||
|
||||
@Schema(title = "Template content",
|
||||
description = "Template content",
|
||||
example = """
|
||||
[${title}]
|
||||
${targetLabel} : ${target}
|
||||
<#if (monitorId??)>${monitorIdLabel} : ${monitorId} </#if>
|
||||
<#if (monitorName??)>${monitorNameLabel} : ${monitorName} </#if>
|
||||
<#if (monitorHost??)>${monitorHostLabel} : ${monitorHost} </#if>
|
||||
${priorityLabel} : ${priority}
|
||||
${triggerTimeLabel} : ${triggerTime}
|
||||
${contentLabel} : ${content}""", accessMode = READ_WRITE)
|
||||
@Size(max = 60000)
|
||||
@Lob
|
||||
@NotBlank
|
||||
private String content;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom", accessMode = READ_ONLY)
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "This record was last modified by", example = "tom", accessMode = READ_ONLY)
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "This record creation time (millisecond timestamp)", accessMode = READ_ONLY)
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record the latest modification time (timestamp in milliseconds)", accessMode = READ_ONLY)
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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.alerter;
|
||||
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
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.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.Table;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.hertzbeat.common.util.JsonUtil;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Single Alert Content Entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_alert_single", indexes = {@Index(name = "unique_fingerprint", columnList = "fingerprint", unique = true)})
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Single Alarm Content Entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class SingleAlert {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "Threshold Id", example = "87584674384", accessMode = READ_ONLY)
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "Fingerprint", example = "alertname:demo")
|
||||
@Column(length = 2048)
|
||||
private String fingerprint;
|
||||
|
||||
@Schema(title = "Labels", example = "{\"alertname\": \"HighCPUUsage\", \"priority\": \"critical\", \"instance\": \"343483943\"}")
|
||||
@Convert(converter = JsonMapAttributeConverter.class)
|
||||
@Column(length = 2048)
|
||||
private Map<String, String> labels;
|
||||
|
||||
@Schema(title = "Annotations", example = "{\"summary\": \"High CPU usage detected\"}")
|
||||
@Convert(converter = JsonMapAttributeConverter.class)
|
||||
@Column(length = 4096)
|
||||
private Map<String, String> annotations;
|
||||
|
||||
@Schema(title = "Content", example = "CPU usage is above 80% for the last 5 minutes on instance server1.example.com.")
|
||||
@Column(length = 4096)
|
||||
private String content;
|
||||
|
||||
@Schema(title = "Status", example = "firing|resolved")
|
||||
private String status;
|
||||
|
||||
@Schema(title = "Trigger Times", example = "1")
|
||||
private Integer triggerTimes;
|
||||
|
||||
@Schema(title = "Start At", example = "1734005477630")
|
||||
private Long startAt;
|
||||
|
||||
@Schema(title = "Active At", example = "1734005477630")
|
||||
private Long activeAt;
|
||||
|
||||
@Schema(title = "End At, when status is resolved has", example = "null")
|
||||
private Long endAt;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom")
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "This record was last modified by", example = "tom")
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "This record creation time (millisecond timestamp)")
|
||||
@CreatedDate
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record the latest modification time (timestamp in milliseconds)")
|
||||
@LastModifiedDate
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime gmtUpdate;
|
||||
|
||||
@Override
|
||||
public SingleAlert clone() {
|
||||
// deep clone
|
||||
return JsonUtil.fromJson(JsonUtil.toJson(this), SingleAlert.class);
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.grafana;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.Transient;
|
||||
import java.io.Serializable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Grafana dashboard entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_grafana_dashboard")
|
||||
@Data
|
||||
@Builder(toBuilder = true)
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Grafana dashboard entity")
|
||||
public class GrafanaDashboard implements Serializable {
|
||||
|
||||
@Id
|
||||
@Schema(description = "Monitor id")
|
||||
private Long monitorId;
|
||||
|
||||
@Schema(description = "Dashboard folderUid")
|
||||
private String folderUid;
|
||||
|
||||
@Schema(description = "Dashboard slug")
|
||||
private String slug;
|
||||
|
||||
@Schema(description = "Dashboard status")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "Dashboard uid")
|
||||
private String uid;
|
||||
|
||||
@Schema(description = "Dashboard url")
|
||||
private String url;
|
||||
|
||||
@Schema(description = "Dashboard version")
|
||||
private Long version;
|
||||
|
||||
@Schema(description = "is enabled")
|
||||
private boolean enabled;
|
||||
|
||||
@Schema(description = "template")
|
||||
@Transient
|
||||
private String template;
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.annotation.CreatedBy;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY;
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_WRITE;
|
||||
|
||||
/**
|
||||
* API Token Entity - stores generated non-expiring API tokens for management and revocation.
|
||||
* <p>
|
||||
* Only "managed" tokens (those generated after this feature was introduced) are stored here.
|
||||
* Legacy tokens are not tracked and continue to work without DB validation.
|
||||
* </p>
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_auth_token")
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "API Token entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class AuthToken {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "primary id", example = "1", accessMode = READ_ONLY)
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "Token name/description", example = "Alert integration token", accessMode = READ_WRITE)
|
||||
@Column(length = 255)
|
||||
private String name;
|
||||
|
||||
@Schema(title = "SHA-256 hash of the token value", accessMode = READ_ONLY)
|
||||
@Column(length = 128, nullable = false, unique = true)
|
||||
private String tokenHash;
|
||||
|
||||
@Schema(title = "Masked token for display", example = "eyJh****xMjM", accessMode = READ_ONLY)
|
||||
@Column(length = 64)
|
||||
private String tokenMask;
|
||||
|
||||
@Schema(title = "Token status: 0-active", accessMode = READ_ONLY)
|
||||
@Column(nullable = false)
|
||||
@Builder.Default
|
||||
private Byte status = 0;
|
||||
|
||||
@Schema(title = "The creator of this token", accessMode = READ_ONLY)
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "Token creation time", accessMode = READ_ONLY)
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Token expiration time, null means never expire", accessMode = READ_ONLY)
|
||||
private LocalDateTime expireTime;
|
||||
|
||||
@Schema(title = "Token last used time", accessMode = READ_ONLY)
|
||||
private LocalDateTime lastUsedTime;
|
||||
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
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
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@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 = 4096)
|
||||
@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(name = "fields", length = 4096)
|
||||
@Convert(converter = JsonMapListAttributeConverter.class)
|
||||
private Map<String, List<String>> fields;
|
||||
|
||||
@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;
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
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;
|
||||
|
||||
/**
|
||||
* collector entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_collector", uniqueConstraints = @UniqueConstraint(columnNames = {"name"}))
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "slave collector entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class Collector {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "primary id", example = "2")
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "collector identity name", description = "collector identity name")
|
||||
@NotBlank(message = "name can not null")
|
||||
private String name;
|
||||
|
||||
@Schema(title = "collector ip", description = "collector remote ip")
|
||||
@NotBlank(message = "ip can not null")
|
||||
private String ip;
|
||||
|
||||
@Schema(title = "collector version", description = "collector version")
|
||||
private String version;
|
||||
|
||||
@Schema(title = "collector status: 0-online 1-offline")
|
||||
@Min(0)
|
||||
private byte status;
|
||||
|
||||
@Schema(title = "collector mode: public or private")
|
||||
private String mode;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom")
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "This record was last modified by")
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "This record creation time (millisecond timestamp)")
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record the latest modification time (timestamp in milliseconds)")
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.Table;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
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;
|
||||
|
||||
/**
|
||||
* collector entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_collector_monitor_bind", indexes = {
|
||||
@Index(name = "idx_collector_monitor_collector", columnList = "collector"),
|
||||
@Index(name = "idx_collector_monitor_monitor_id", columnList = "monitor_id")
|
||||
})
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "slave collector monitor bind entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class CollectorMonitorBind {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "primary id", example = "23")
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "collector name", example = "87432674384")
|
||||
private String collector;
|
||||
|
||||
@Schema(title = "monitor ID", example = "87432674336")
|
||||
@Column(name = "monitor_id")
|
||||
private Long monitorId;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom")
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "This record was last modified by")
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "This record creation time (millisecond timestamp)")
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record the latest modification time (timestamp in milliseconds)")
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Lob;
|
||||
import jakarta.persistence.Table;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
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;
|
||||
|
||||
/**
|
||||
* monitor define entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_define")
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "monitor define entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class Define {
|
||||
|
||||
@Id
|
||||
@Schema(title = "app", example = "websocket")
|
||||
private String app;
|
||||
|
||||
@Lob
|
||||
@Schema(title = "define content", description = "define yml content")
|
||||
private String content;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom")
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "This record was last modified by")
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "This record creation time (millisecond timestamp)")
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record the latest modification time (timestamp in milliseconds)")
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY;
|
||||
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.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Common Config Entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_config")
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Common server config entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class GeneralConfig {
|
||||
|
||||
@Id
|
||||
@Schema(title = "Config type: email sms, primary key ", description = "Config type: email sms, primary key ",
|
||||
accessMode = READ_WRITE)
|
||||
@NotBlank(message = "ip can not null")
|
||||
private String type;
|
||||
|
||||
@Schema(title = "Config content", description = "Config content,formatjson", accessMode = READ_WRITE)
|
||||
@Column(length = 8192)
|
||||
private String content;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom", accessMode = READ_ONLY)
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "This record was last modified by", example = "tom", accessMode = READ_ONLY)
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "This record creation time (millisecond timestamp)", accessMode = READ_ONLY)
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record the latest modification time (timestamp in milliseconds)", accessMode = READ_ONLY)
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import tools.jackson.core.type.TypeReference;
|
||||
import jakarta.persistence.AttributeConverter;
|
||||
import jakarta.persistence.Converter;
|
||||
import java.util.List;
|
||||
import org.apache.hertzbeat.common.util.JsonUtil;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* json str to list Byte converter
|
||||
*/
|
||||
@Converter
|
||||
@Component
|
||||
public class JsonByteListAttributeConverter implements AttributeConverter<List<Byte>, String> {
|
||||
|
||||
@Override
|
||||
public String convertToDatabaseColumn(List<Byte> attribute) {
|
||||
return JsonUtil.toJson(attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Byte> convertToEntityAttribute(String dbData) {
|
||||
TypeReference<List<Byte>> typeReference = new TypeReference<>() {};
|
||||
return JsonUtil.fromJson(dbData, typeReference);
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import tools.jackson.core.type.TypeReference;
|
||||
import jakarta.persistence.AttributeConverter;
|
||||
import jakarta.persistence.Converter;
|
||||
import java.util.List;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.hertzbeat.common.util.JsonUtil;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* json str to id list
|
||||
*/
|
||||
@Converter
|
||||
@Component
|
||||
public class JsonLongListAttributeConverter implements AttributeConverter<List<Long>, String> {
|
||||
@Override
|
||||
public String convertToDatabaseColumn(List<Long> attribute) {
|
||||
return JsonUtil.toJson(attribute);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> convertToEntityAttribute(String dbData) {
|
||||
if (StringUtils.isBlank(dbData)) {
|
||||
return List.of();
|
||||
}
|
||||
if (!JsonUtil.isJsonStr(dbData) && StringUtils.isNumeric(dbData)) {
|
||||
return List.of(Long.parseLong(dbData));
|
||||
}
|
||||
TypeReference<List<Long>> typeReference = new TypeReference<>() {
|
||||
};
|
||||
List<Long> longList = JsonUtil.fromJson(dbData, typeReference);
|
||||
if (longList == null && !dbData.isEmpty()) {
|
||||
if (StringUtils.isNumeric(dbData)) {
|
||||
return List.of(Long.parseLong(dbData));
|
||||
} else {
|
||||
throw new NumberFormatException("String convert to Long error");
|
||||
}
|
||||
} else {
|
||||
return longList;
|
||||
}
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import jakarta.persistence.AttributeConverter;
|
||||
import jakarta.persistence.Converter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.hertzbeat.common.util.JsonUtil;
|
||||
import org.springframework.stereotype.Component;
|
||||
import tools.jackson.core.type.TypeReference;
|
||||
|
||||
/**
|
||||
* json map list str converter
|
||||
*/
|
||||
@Converter
|
||||
@Component
|
||||
public class JsonMapListAttributeConverter implements AttributeConverter<Map<String, List<String>>, String> {
|
||||
|
||||
@Override
|
||||
public String convertToDatabaseColumn(Map<String, List<String>> attribute) {
|
||||
return JsonUtil.toJson(attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> convertToEntityAttribute(String dbData) {
|
||||
TypeReference<Map<String, List<String>>> typeReference = new TypeReference<>() {};
|
||||
return JsonUtil.fromJson(dbData, typeReference);
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import tools.jackson.core.type.TypeReference;
|
||||
import jakarta.persistence.AttributeConverter;
|
||||
import jakarta.persistence.Converter;
|
||||
import java.util.List;
|
||||
import org.apache.hertzbeat.common.util.JsonUtil;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* json str to list paramDefine.Option
|
||||
*/
|
||||
@Converter
|
||||
@Component
|
||||
public class JsonOptionListAttributeConverter implements AttributeConverter<List<ParamDefine.Option>, String> {
|
||||
|
||||
@Override
|
||||
public String convertToDatabaseColumn(List<ParamDefine.Option> attribute) {
|
||||
return JsonUtil.toJson(attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ParamDefine.Option> convertToEntityAttribute(String dbData) {
|
||||
TypeReference<List<ParamDefine.Option>> typeReference = new TypeReference<>() {};
|
||||
return JsonUtil.fromJson(dbData, typeReference);
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import tools.jackson.core.type.TypeReference;
|
||||
import jakarta.persistence.AttributeConverter;
|
||||
import jakarta.persistence.Converter;
|
||||
import java.util.List;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.hertzbeat.common.util.JsonUtil;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Convert the list of strings to a JSON string
|
||||
*/
|
||||
@Converter
|
||||
@Component
|
||||
public class JsonStringListAttributeConverter implements AttributeConverter<List<String>, String> {
|
||||
@Override
|
||||
public String convertToDatabaseColumn(List<String> attribute) {
|
||||
return JsonUtil.toJson(attribute);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> convertToEntityAttribute(String dbData) {
|
||||
if (StringUtils.isBlank(dbData)) {
|
||||
return List.of();
|
||||
}
|
||||
if (!JsonUtil.isJsonStr(dbData)) {
|
||||
return List.of(dbData);
|
||||
}
|
||||
TypeReference<List<String>> typeReference = new TypeReference<>() {
|
||||
};
|
||||
List<String> stringList = JsonUtil.fromJson(dbData, typeReference);
|
||||
if (stringList == null && !dbData.isEmpty()) {
|
||||
return List.of(dbData);
|
||||
} else {
|
||||
return stringList;
|
||||
}
|
||||
}
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY;
|
||||
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.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Objects;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Label Entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_tag")
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Label Entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class Label {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "Primary key index ID", example = "87584674384", accessMode = READ_ONLY)
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "Label Field", example = "app", accessMode = READ_WRITE)
|
||||
@NotBlank(message = "name can not null")
|
||||
private String name;
|
||||
|
||||
@Schema(title = "Label Value", example = "23", accessMode = READ_WRITE)
|
||||
@Column(length = 2048)
|
||||
private String tagValue;
|
||||
|
||||
@Schema(title = "Label Description", example = "Used for monitoring mysql", accessMode = READ_WRITE)
|
||||
private String description;
|
||||
|
||||
@Schema(title = "Tag type 0: Auto-generated 1: user-generated 2: system preset",
|
||||
accessMode = READ_WRITE)
|
||||
@Min(0)
|
||||
@Max(3)
|
||||
private Byte type;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom", accessMode = READ_ONLY)
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "The modifier of this record", example = "tom", accessMode = READ_ONLY)
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "Record create time", example = "1612198922000", accessMode = READ_ONLY)
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record modify time", example = "1612198444000", accessMode = READ_ONLY)
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Label tag = (Label) o;
|
||||
return Objects.equals(name, tag.name) && Objects.equals(tagValue, tag.tagValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 7;
|
||||
hash = 13 * hash + (name == null ? 0 : name.hashCode()) + (tagValue == null ? 0 : tagValue.hashCode());
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
|
||||
/**
|
||||
* Metrics Favorite Entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_metrics_favorite",
|
||||
uniqueConstraints = @UniqueConstraint(columnNames = {"creator", "monitor_id", "metrics_name"}))
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class MetricsFavorite {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@NotBlank(message = "Creator cannot be null or blank")
|
||||
@Size(max = 255, message = "Creator length cannot exceed 255 characters")
|
||||
@Column(name = "creator", nullable = false)
|
||||
private String creator;
|
||||
|
||||
@NotNull(message = "Monitor ID cannot be null")
|
||||
@Column(name = "monitor_id", nullable = false)
|
||||
private Long monitorId;
|
||||
|
||||
@NotBlank(message = "Metrics name cannot be null or blank")
|
||||
@Size(max = 255, message = "Metrics name length cannot exceed 255 characters")
|
||||
@Column(name = "metrics_name", nullable = false)
|
||||
private String metricsName;
|
||||
|
||||
@CreatedDate
|
||||
@Column(name = "create_time", updatable = false)
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY;
|
||||
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.Index;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.hertzbeat.common.entity.alerter.JsonMapAttributeConverter;
|
||||
import org.apache.hertzbeat.common.support.valid.HostValid;
|
||||
import org.apache.hertzbeat.common.util.JsonUtil;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Monitor Entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_monitor", indexes = {
|
||||
@Index(name = "idx_hzb_monitor_app", columnList = "app"),
|
||||
@Index(name = "idx_hzb_monitor_instance", columnList = "instance"),
|
||||
@Index(name = "idx_hzb_monitor_name", columnList = "name")
|
||||
})
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Monitor Entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class Monitor {
|
||||
|
||||
@Id
|
||||
@Schema(title = "Monitor task ID", example = "87584674384", accessMode = READ_ONLY)
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "Collect task ID", example = "43243543543", accessMode = READ_ONLY)
|
||||
private Long jobId;
|
||||
|
||||
@Schema(title = "task name", example = "Api-TanCloud.cn", accessMode = READ_WRITE)
|
||||
@Size(max = 100)
|
||||
private String name;
|
||||
|
||||
@Schema(title = "Type of monitoring", example = "TanCloud", accessMode = READ_WRITE)
|
||||
@Size(max = 100)
|
||||
private String app;
|
||||
|
||||
@Schema(title = "Scrape type: static | http_sd | dns_sd | zookeeper_sd", example = "static", accessMode = READ_WRITE)
|
||||
@Size(max = 100)
|
||||
private String scrape;
|
||||
|
||||
@Schema(title = "the monitor target: ip/domain+port or ip/domain", example = "192.167.25.11:8081", accessMode = READ_WRITE)
|
||||
@Size(max = 100)
|
||||
@HostValid
|
||||
private String instance;
|
||||
|
||||
@Schema(title = "Monitoring of the acquisition interval time in seconds", example = "600", accessMode = READ_WRITE)
|
||||
@Min(10)
|
||||
private Integer intervals;
|
||||
|
||||
@Schema(title = "Schedule type: interval | cron", example = "interval", accessMode = READ_WRITE)
|
||||
@Size(max = 20)
|
||||
private String scheduleType;
|
||||
|
||||
@Schema(title = "Cron expression when scheduleType is cron", example = "0/5 * * * * ?", accessMode = READ_WRITE)
|
||||
@Size(max = 100)
|
||||
private String cronExpression;
|
||||
|
||||
@Schema(title = "Task status 0: Paused, 1: Up, 2: Down", accessMode = READ_WRITE)
|
||||
@Min(0)
|
||||
@Max(4)
|
||||
private byte status;
|
||||
|
||||
@Schema(title = "Task type 0: Normal, 1: push auto create, 2: discovery auto create")
|
||||
private byte type;
|
||||
|
||||
@Schema(title = "task label", example = "{env:test}", accessMode = READ_WRITE)
|
||||
@Convert(converter = JsonMapAttributeConverter.class)
|
||||
@Column(length = 4096)
|
||||
private Map<String, String> labels;
|
||||
|
||||
@Schema(title = "task annotations", example = "{summary:this task looks good}", accessMode = READ_WRITE)
|
||||
@Convert(converter = JsonMapAttributeConverter.class)
|
||||
@Column(length = 4096)
|
||||
private Map<String, String> annotations;
|
||||
|
||||
@Schema(title = "Monitor note description", example = "Availability monitoring of the SAAS website TanCloud", accessMode = READ_WRITE)
|
||||
@Size(max = 255)
|
||||
private String description;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom", accessMode = READ_ONLY)
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "The modifier of this record", example = "tom", accessMode = READ_ONLY)
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "Record create time", example = "2024-07-02T20:09:34.903217", accessMode = READ_ONLY)
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record modify time", example = "2024-07-02T20:09:34.903217", accessMode = READ_ONLY)
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
|
||||
@Override
|
||||
public Monitor clone() {
|
||||
return JsonUtil.fromJson(JsonUtil.toJson(this), getClass());
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.Table;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Monitor Bind
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_monitor_bind", indexes = {
|
||||
@Index(name = "index_monitor_bind", columnList = "biz_id"),
|
||||
@Index(name = "index_monitor_bin", columnList = "monitor_id")
|
||||
})
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "relation between monitor")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class MonitorBind {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "primary id", example = "23")
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "key string: ip:port")
|
||||
private String keyStr;
|
||||
|
||||
@Schema(title = "connect bind id", example = "87432674384")
|
||||
private Long bizId;
|
||||
|
||||
@Schema(title = "monitor ID", example = "87432674336")
|
||||
@Column(name = "monitor_id")
|
||||
private Long monitorId;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom")
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "This record was last modified by")
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "This record creation time (millisecond timestamp)")
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record the latest modification time (timestamp in milliseconds)")
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
}
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY;
|
||||
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.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.hertzbeat.common.util.JsonUtil;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
/**
|
||||
* Monitor parameter values
|
||||
*/
|
||||
@Entity
|
||||
@Table(
|
||||
name = "hzb_param",
|
||||
indexes = {@Index(name = "idx_hzb_param_monitor_id", columnList = "monitor_id")},
|
||||
uniqueConstraints = {@UniqueConstraint(name = "uk_hzb_param_monitor_field", columnNames = {"monitor_id", "field"})}
|
||||
)
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Parameter Entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class Param {
|
||||
|
||||
/**
|
||||
* Parameter primary key index ID
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "Parameter primary key index ID", example = "87584674384", accessMode = READ_ONLY)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* Monitor ID
|
||||
*/
|
||||
@Schema(title = "Monitor task ID", example = "875846754543", accessMode = READ_WRITE)
|
||||
@Column(name = "monitor_id")
|
||||
private Long monitorId;
|
||||
|
||||
/**
|
||||
* Parameter Field Identifier
|
||||
*/
|
||||
@Schema(title = "Parameter identifier field", example = "port", accessMode = READ_WRITE)
|
||||
@Size(max = 100)
|
||||
@Column(name = "field")
|
||||
@NotBlank(message = "field can not null")
|
||||
private String field;
|
||||
|
||||
/**
|
||||
* Param Value
|
||||
*/
|
||||
@Schema(title = "parameter values", example = "8080", accessMode = READ_WRITE)
|
||||
@Size(max = 8126)
|
||||
@Column(length = 8126)
|
||||
private String paramValue;
|
||||
|
||||
/**
|
||||
* Parameter type 0: number 1: string 2: encrypted string 3: json string mapped by map
|
||||
*/
|
||||
@Schema(title = "Parameter types 0: number 1: string 2: encrypted string 3:map mapped json string 4:arrays string",
|
||||
accessMode = READ_WRITE)
|
||||
@Min(0)
|
||||
private byte type;
|
||||
|
||||
/**
|
||||
* Record create time
|
||||
*/
|
||||
@Schema(title = "Record create time", example = "1612198922000", accessMode = READ_ONLY)
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
/**
|
||||
* Record the latest modification time
|
||||
*/
|
||||
@Schema(title = "Record modify time", example = "1612198444000", accessMode = READ_ONLY)
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
|
||||
@Override
|
||||
public Param clone() {
|
||||
// deep clone
|
||||
return JsonUtil.fromJson(JsonUtil.toJson(this), getClass());
|
||||
}
|
||||
}
|
||||
+212
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY;
|
||||
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.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.hertzbeat.common.entity.alerter.JsonMapAttributeConverter;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Monitoring parameter definitions
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_param_define")
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Parameter structure definition entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class ParamDefine {
|
||||
|
||||
/**
|
||||
* Parameter Structure ID
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "Parameter structure ID", example = "87584674384", accessMode = READ_ONLY)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* Monitoring application type name
|
||||
*/
|
||||
@Schema(title = "Type of monitoring", example = "TanCloud", accessMode = READ_WRITE)
|
||||
private String app;
|
||||
|
||||
/**
|
||||
* Parameter field external display name
|
||||
* Port
|
||||
*/
|
||||
@Schema(description = "The parameter field displays the internationalized name", example = "{zh-CN: '端口'}",
|
||||
accessMode = READ_WRITE)
|
||||
@Convert(converter = JsonMapAttributeConverter.class)
|
||||
@SuppressWarnings("JpaAttributeTypeInspection")
|
||||
@Column(length = 2048)
|
||||
private Map<String, String> name;
|
||||
|
||||
/**
|
||||
* Parameter Field Identifier
|
||||
*/
|
||||
@Schema(title = "Parameter field identifier", example = "port", accessMode = READ_WRITE)
|
||||
private String field;
|
||||
|
||||
/**
|
||||
* Field type, style (mostly map the input tag type attribute)
|
||||
*/
|
||||
@Schema(title = "Field type, style (mostly map the input tag type attribute)", example = "number", accessMode = READ_WRITE)
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* Is it mandatory true-required false-optional
|
||||
*/
|
||||
@Schema(title = "Is it mandatory true-required false-optional", example = "true", accessMode = READ_WRITE)
|
||||
private boolean required = false;
|
||||
|
||||
/**
|
||||
* Parameter Default Value
|
||||
*/
|
||||
@Schema(title = "Parameter default values", example = "12", accessMode = READ_WRITE)
|
||||
private String defaultValue;
|
||||
|
||||
/**
|
||||
* Parameter input box prompt information
|
||||
*/
|
||||
@Schema(title = "Parameter input field prompt information", example = "enter your password", accessMode = READ_WRITE)
|
||||
private String placeholder;
|
||||
|
||||
/**
|
||||
* When type is number, use range to represent the range eg: 0-233
|
||||
*/
|
||||
@Schema(title = "When type is number, the range is represented by the range interval", example = "[0,233]", accessMode = READ_WRITE)
|
||||
@Column(name = "param_range")
|
||||
private String range;
|
||||
|
||||
/**
|
||||
* When type is text, use limit to indicate the limit size of the string. The maximum is 255
|
||||
*/
|
||||
@Schema(title = "When type is text, use limit to indicate the limit size of the string. The maximum is 255",
|
||||
example = "30", accessMode = READ_WRITE)
|
||||
@Column(name = "param_limit")
|
||||
private Short limit;
|
||||
|
||||
/**
|
||||
* When the type is radio radio box, checkbox checkbox, options represents a list of optional values
|
||||
* eg: {
|
||||
* "key1":"value1",
|
||||
* "key2":"value2"
|
||||
* }
|
||||
* key-Value display label
|
||||
* value-True value
|
||||
*/
|
||||
@Schema(description = "When the type is radio radio box, checkbox checkbox, options represents a list of optional values",
|
||||
example = "{key1,value1}", accessMode = READ_WRITE)
|
||||
@Column(name = "param_options", length = 2048)
|
||||
@Convert(converter = JsonOptionListAttributeConverter.class)
|
||||
private List<Option> options;
|
||||
|
||||
/**
|
||||
* Valid when type is key-value, indicating the alias description of the key
|
||||
*/
|
||||
@Schema(title = "Valid when type is key-value, indicating the alias description of the key", example = "Name", accessMode = READ_WRITE)
|
||||
private String keyAlias;
|
||||
|
||||
/**
|
||||
* Valid when type is key-value, indicating the alias description of value type
|
||||
*/
|
||||
@Schema(title = "Valid when type is key-value, indicating the alias description of value type", example = "Value", accessMode = READ_WRITE)
|
||||
private String valueAlias;
|
||||
|
||||
/**
|
||||
* Is it an advanced hidden parameter true-yes false-no
|
||||
*/
|
||||
@Schema(title = "Is it an advanced hidden parameter true-yes false-no", example = "true", accessMode = READ_WRITE)
|
||||
private boolean hide = false;
|
||||
|
||||
/**
|
||||
* The creator of this record
|
||||
*/
|
||||
@Schema(title = "The creator of this record", example = "tom", accessMode = READ_ONLY)
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
/**
|
||||
* This record was last modified by
|
||||
*/
|
||||
@Schema(title = "The modifier of this record", example = "tom", accessMode = READ_ONLY)
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
/**
|
||||
* Record create time
|
||||
*/
|
||||
@Schema(title = "Record create time", example = "1612198922000", accessMode = READ_ONLY)
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
/**
|
||||
* Record the latest modification time
|
||||
*/
|
||||
@Schema(title = "Record modify time", example = "1612198444000", accessMode = READ_ONLY)
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
|
||||
/**
|
||||
* Depends on which parameters
|
||||
*/
|
||||
@Schema(title = "Depends on which parameters", example = "{field:[value1, value2, ...]}", accessMode = READ_WRITE)
|
||||
@Convert(converter = JsonMapAttributeConverter.class)
|
||||
private Map<String, List<Object>> depend;
|
||||
|
||||
/**
|
||||
* Parameter option configuration
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public static final class Option {
|
||||
/**
|
||||
* value display label
|
||||
*/
|
||||
private String label;
|
||||
/**
|
||||
* optional value
|
||||
*/
|
||||
private String value;
|
||||
}
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY;
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_WRITE;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.Objects;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.hertzbeat.common.constants.PluginType;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
/**
|
||||
* Plugin Entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_plugin_item")
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "PluginItem Entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class PluginItem {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "Plugin Primary key index ID", example = "87584674384", accessMode = READ_ONLY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "metadata_id")
|
||||
@JsonIgnore
|
||||
private PluginMetadata pluginMetadata;
|
||||
|
||||
@Schema(title = "Plugin implementation class full path", example = "org.apache.hertzbeat.plugin.impl.DemoPluginImpl", accessMode = READ_WRITE)
|
||||
private String classIdentifier;
|
||||
|
||||
@Schema(title = "Plugin type", example = "POST_ALERT", accessMode = READ_WRITE)
|
||||
@Enumerated(EnumType.STRING)
|
||||
private PluginType type;
|
||||
|
||||
public PluginItem(String classIdentifier, PluginType type) {
|
||||
this.classIdentifier = classIdentifier;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
PluginItem that = (PluginItem) o;
|
||||
return Objects.equals(id, that.id) && Objects.equals(classIdentifier, that.classIdentifier) && type == that.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, classIdentifier, type);
|
||||
}
|
||||
}
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY;
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_WRITE;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.annotation.CreatedBy;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
/**
|
||||
* Plugin Entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_plugin_metadata")
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Plugin Entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class PluginMetadata {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "Plugin Primary key index ID", example = "87584674384", accessMode = READ_ONLY)
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "plugin name", example = "notification plugin", accessMode = READ_WRITE)
|
||||
@NotNull
|
||||
private String name;
|
||||
|
||||
@Schema(title = "Plugin activation status", example = "true", accessMode = READ_WRITE)
|
||||
private Boolean enableStatus;
|
||||
|
||||
@Schema(title = "Jar file path", example = "true", accessMode = READ_WRITE)
|
||||
private String jarFilePath;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
PluginMetadata that = (PluginMetadata) o;
|
||||
return Objects.equals(id, that.id) && Objects.equals(name, that.name) && Objects.equals(enableStatus, that.enableStatus) && Objects.equals(jarFilePath,
|
||||
that.jarFilePath) && Objects.equals(creator, that.creator) && Objects.equals(gmtCreate, that.gmtCreate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, name, enableStatus, jarFilePath, creator, gmtCreate);
|
||||
}
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom", accessMode = READ_ONLY)
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "Record create time", example = "1612198922000", accessMode = READ_ONLY)
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@OneToMany(targetEntity = PluginItem.class, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "metadata_id", referencedColumnName = "id")
|
||||
private List<PluginItem> items;
|
||||
|
||||
@Schema(title = "Param count", example = "1", accessMode = READ_WRITE)
|
||||
private Integer paramCount;
|
||||
|
||||
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.hertzbeat.common.entity.alerter.JsonMapAttributeConverter;
|
||||
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;
|
||||
|
||||
/**
|
||||
* status page component entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_status_page_component")
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "status page component entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class StatusPageComponent {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "ID", example = "87584674384")
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "org id", example = "1234")
|
||||
private Long orgId;
|
||||
|
||||
@Schema(title = "component name", example = "Gateway")
|
||||
@NotBlank
|
||||
private String name;
|
||||
|
||||
@Schema(title = "component desc", example = "TanCloud Gateway")
|
||||
private String description;
|
||||
|
||||
@Schema(title = "component label", example = "{env:test}", accessMode = READ_WRITE)
|
||||
@Convert(converter = JsonMapAttributeConverter.class)
|
||||
@Column(length = 4096)
|
||||
private Map<String, String> labels;
|
||||
|
||||
@Schema(title = "calculate status method: 0-auto 1-manual", example = "0")
|
||||
private byte method;
|
||||
|
||||
@Schema(title = "config state when use manual method: 0-Normal 1-Abnormal 2-unknown", example = "0")
|
||||
private byte configState;
|
||||
|
||||
@Schema(title = "component current state: 0-Normal 1-Abnormal 2-unknown", example = "0")
|
||||
private byte state;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom")
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "The modifier of this record", example = "tom")
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "Record create time", example = "1612198922000")
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record modify time", example = "1612198444000")
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
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;
|
||||
|
||||
/**
|
||||
* status page history entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_status_page_history")
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "status page component history entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class StatusPageHistory {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "ID", example = "87584674384")
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "component id", example = "1234")
|
||||
private Long componentId;
|
||||
|
||||
@Schema(title = "component state: 0-Normal 1-Abnormal 2-unknown", example = "0")
|
||||
private byte state;
|
||||
|
||||
@Schema(title = "state calculate timestamp", example = "4248574985744")
|
||||
private Long timestamp;
|
||||
|
||||
@Schema(title = "state uptime percentage", example = "99.99")
|
||||
private Double uptime;
|
||||
|
||||
@Schema(title = "state abnormal time(s)", example = "1000")
|
||||
private Integer abnormal;
|
||||
|
||||
@Schema(title = "state unknown time(s)", example = "1000")
|
||||
private Integer unknowing;
|
||||
|
||||
@Schema(title = "state normal tim(s)", example = "1000")
|
||||
private Integer normal;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom")
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "The modifier of this record", example = "tom")
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "Record create time", example = "1612198922000")
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record modify time", example = "1612198444000")
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.ConstraintMode;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.ForeignKey;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.JoinTable;
|
||||
import jakarta.persistence.ManyToMany;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
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;
|
||||
|
||||
/**
|
||||
* status page incident entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_status_page_incident")
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "status page incident entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class StatusPageIncident {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "ID", example = "87584674384")
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "org id", example = "1234")
|
||||
private Long orgId;
|
||||
|
||||
@Schema(title = "incident name", example = "Gateway")
|
||||
@NotBlank
|
||||
private String name;
|
||||
|
||||
@Schema(title = "incident current state: 0-Investigating 1-Identified 2-Monitoring 3-Resolved", example = "0")
|
||||
private byte state;
|
||||
|
||||
@Schema(title = "incident start Investigating timestamp", example = "4248574985744")
|
||||
private Long startTime;
|
||||
|
||||
@Schema(title = "incident end Resolved timestamp", example = "4248574985744")
|
||||
private Long endTime;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom")
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "The modifier of this record", example = "tom")
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "Record create time", example = "1612198922000")
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record modify time", example = "1612198444000")
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
|
||||
@Schema(title = "status page components")
|
||||
@ManyToMany(targetEntity = StatusPageComponent.class, cascade = CascadeType.MERGE, fetch = FetchType.EAGER)
|
||||
@JoinTable(name = "hzb_status_page_incident_component_bind",
|
||||
foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT),
|
||||
inverseForeignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT),
|
||||
joinColumns = {@JoinColumn(name = "incident_id", referencedColumnName = "id")},
|
||||
inverseJoinColumns = {@JoinColumn(name = "component_id", referencedColumnName = "id")})
|
||||
private List<StatusPageComponent> components;
|
||||
|
||||
@Schema(title = "status page incident content")
|
||||
@OneToMany(targetEntity = StatusPageIncidentContent.class, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "incident_id", referencedColumnName = "id")
|
||||
private Set<StatusPageIncidentContent> contents;
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.Table;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
/**
|
||||
* status page incident component bind entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_status_page_incident_component_bind", indexes = {
|
||||
@Index(name = "index_incident_component", columnList = "incident_id"),
|
||||
})
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Incident Component Bind")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class StatusPageIncidentComponentBind {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "Identity", example = "87584674384")
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "Incident ID", example = "87432674384")
|
||||
@Column(name = "incident_id")
|
||||
private Long incidentId;
|
||||
|
||||
@Schema(title = "Component ID", example = "87432674336")
|
||||
@Column(name = "component_id")
|
||||
private Long componentId;
|
||||
|
||||
@Schema(title = "Record create time", example = "1612198922000")
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record modify time", example = "1612198444000")
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
|
||||
}
|
||||
+87
@@ -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.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.common.entity.manager;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
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;
|
||||
|
||||
/**
|
||||
* status page incident entity content.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_status_page_incident_content")
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "status page incident content entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class StatusPageIncidentContent {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "ID", example = "87584674384")
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "org id", example = "1234")
|
||||
@Column(name = "incident_id")
|
||||
private Long incidentId;
|
||||
|
||||
@Schema(title = "incident content message", example = "we find the gateway connection timeout")
|
||||
@NotBlank
|
||||
private String message;
|
||||
|
||||
@Schema(title = "incident state: 0-Investigating 1-Identified 2-Monitoring 3-Resolved", example = "0")
|
||||
private byte state;
|
||||
|
||||
@Schema(title = "incident content message timestamp", example = "4248574985744")
|
||||
private Long timestamp;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom")
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "The modifier of this record", example = "tom")
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "Record create time", example = "1612198922000")
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record modify time", example = "1612198444000")
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
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;
|
||||
|
||||
/**
|
||||
* status page org entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_status_page_org")
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "status page org entity")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class StatusPageOrg {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(title = "ID", example = "87584674384")
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "org name", example = "TanCloud")
|
||||
@NotBlank
|
||||
private String name;
|
||||
|
||||
@Schema(title = "org desc", example = "TanCloud inc")
|
||||
@NotBlank
|
||||
private String description;
|
||||
|
||||
@Schema(title = "org home url", example = "https://tancloud.com")
|
||||
@NotBlank
|
||||
private String home;
|
||||
|
||||
@Schema(title = "org logo url", example = "logo.svg url")
|
||||
@NotBlank
|
||||
private String logo;
|
||||
|
||||
@Schema(title = "org feedback issue url", example = "contact@email.com")
|
||||
private String feedback;
|
||||
|
||||
@Schema(title = "org theme background color", example = "#ffffff")
|
||||
private String color;
|
||||
|
||||
@Schema(title = "org current state: 0-All Systems Operational 1-Some Systems Abnormal 2-All Systems Abnormal ",
|
||||
example = "0")
|
||||
private byte state;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom")
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "The modifier of this record", example = "tom")
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "Record create time", example = "1612198922000")
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record modify time", example = "1612198444000")
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import jakarta.persistence.AttributeConverter;
|
||||
import jakarta.persistence.Converter;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZonedDateTime;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* zone data time to OffsetDateTime
|
||||
*/
|
||||
@Converter
|
||||
@Component
|
||||
public class ZonedDateTimeAttributeConverter implements AttributeConverter<ZonedDateTime, OffsetDateTime> {
|
||||
|
||||
@Override
|
||||
public OffsetDateTime convertToDatabaseColumn(ZonedDateTime attribute) {
|
||||
if (attribute == null) {
|
||||
return null;
|
||||
}
|
||||
return attribute.toOffsetDateTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZonedDateTime convertToEntityAttribute(OffsetDateTime dbData) {
|
||||
if (dbData == null) {
|
||||
return null;
|
||||
}
|
||||
return dbData.toZonedDateTime();
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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.push;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
/**
|
||||
* push metrics entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_push_metrics", indexes = {
|
||||
@Index(name = "idx_push_metrics_monitor_id", columnList = "monitor_id"),
|
||||
@Index(name = "idx_push_metrics_time", columnList = "time")
|
||||
})
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class PushMetrics {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
private Long monitorId;
|
||||
private Long time;
|
||||
private String metrics;
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.warehouse;
|
||||
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY;
|
||||
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.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* metrics history data entity
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "hzb_history", indexes = {
|
||||
@Index(name = "idx_hzb_history_instance", columnList = "instance"),
|
||||
@Index(name = "idx_hzb_history_app", columnList = "app"),
|
||||
@Index(name = "idx_hzb_history_metrics", columnList = "metrics"),
|
||||
@Index(name = "idx_hzb_history_metric", columnList = "metric")
|
||||
})
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Metrics History Data Entity")
|
||||
public class History {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Schema(description = "Metric data history entity primary key index ID", example = "87584674384", accessMode = READ_ONLY)
|
||||
private Long id;
|
||||
|
||||
@Schema(title = "Monitoring instance", example = "127.0.0.1:8080", accessMode = READ_WRITE)
|
||||
private String instance;
|
||||
|
||||
@Schema(title = "Monitoring Type mysql oracle db2")
|
||||
private String app;
|
||||
|
||||
@Schema(title = "Monitoring Metrics innodb disk cpu")
|
||||
private String metrics;
|
||||
|
||||
@Schema(title = "Monitoring Metric usage speed count")
|
||||
private String metric;
|
||||
|
||||
@Column(length = 5000)
|
||||
private String metricLabels;
|
||||
|
||||
@Schema(title = "Metric Type 0: Number 1:String")
|
||||
private Byte metricType;
|
||||
|
||||
@Schema(title = "Metric String Value")
|
||||
@Column(length = 2048)
|
||||
private String str;
|
||||
|
||||
@Schema(title = "Metric Integer Value")
|
||||
private Integer int32;
|
||||
|
||||
@Schema(title = "Metric Number Value")
|
||||
private Double dou;
|
||||
|
||||
@Schema(title = "Collect Time")
|
||||
private Long time;
|
||||
|
||||
}
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* 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.queue.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.common.constants.DataQueueConstants;
|
||||
import org.apache.hertzbeat.common.entity.log.LogEntry;
|
||||
import org.apache.hertzbeat.common.entity.message.CollectRep;
|
||||
import org.apache.hertzbeat.common.queue.CommonDataQueue;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
/**
|
||||
* common data queue implement memory
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(
|
||||
prefix = DataQueueConstants.PREFIX,
|
||||
name = DataQueueConstants.NAME,
|
||||
havingValue = DataQueueConstants.IN_MEMORY,
|
||||
matchIfMissing = true
|
||||
)
|
||||
@Slf4j
|
||||
@Primary
|
||||
public class InMemoryCommonDataQueue implements CommonDataQueue, DisposableBean {
|
||||
|
||||
private final LinkedBlockingQueue<CollectRep.MetricsData> metricsDataToAlertQueue;
|
||||
private final LinkedBlockingQueue<CollectRep.MetricsData> metricsDataToStorageQueue;
|
||||
private final LinkedBlockingQueue<CollectRep.MetricsData> serviceDiscoveryDataQueue;
|
||||
private final LinkedBlockingQueue<LogEntry> logEntryQueue;
|
||||
private final LinkedBlockingQueue<LogEntry> logEntryToStorageQueue;
|
||||
|
||||
public InMemoryCommonDataQueue() {
|
||||
metricsDataToAlertQueue = new LinkedBlockingQueue<>();
|
||||
metricsDataToStorageQueue = new LinkedBlockingQueue<>();
|
||||
serviceDiscoveryDataQueue = new LinkedBlockingQueue<>();
|
||||
logEntryQueue = new LinkedBlockingQueue<>();
|
||||
logEntryToStorageQueue = new LinkedBlockingQueue<>();
|
||||
}
|
||||
|
||||
public Map<String, Integer> getQueueSizeMetricsInfo() {
|
||||
Map<String, Integer> metrics = new HashMap<>(8);
|
||||
metrics.put("metricsDataToAlertQueue", metricsDataToAlertQueue.size());
|
||||
metrics.put("metricsDataToStorageQueue", metricsDataToStorageQueue.size());
|
||||
metrics.put("logEntryQueue", logEntryQueue.size());
|
||||
metrics.put("logEntryToStorageQueue", logEntryToStorageQueue.size());
|
||||
return metrics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectRep.MetricsData pollServiceDiscoveryData() throws InterruptedException {
|
||||
return serviceDiscoveryDataQueue.take();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectRep.MetricsData pollMetricsDataToAlerter() throws InterruptedException {
|
||||
return metricsDataToAlertQueue.take();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectRep.MetricsData pollMetricsDataToStorage() throws InterruptedException {
|
||||
return metricsDataToStorageQueue.take();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMetricsData(CollectRep.MetricsData metricsData) {
|
||||
metricsDataToAlertQueue.offer(metricsData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMetricsDataToStorage(CollectRep.MetricsData metricsData) {
|
||||
metricsDataToStorageQueue.offer(metricsData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendServiceDiscoveryData(CollectRep.MetricsData metricsData) {
|
||||
serviceDiscoveryDataQueue.offer(metricsData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendLogEntry(LogEntry logEntry) {
|
||||
logEntryQueue.offer(logEntry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LogEntry pollLogEntry() throws InterruptedException {
|
||||
return logEntryQueue.take();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendLogEntryToStorage(LogEntry logEntry) {
|
||||
logEntryToStorageQueue.offer(logEntry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LogEntry pollLogEntryToStorage() throws InterruptedException {
|
||||
return logEntryToStorageQueue.take();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendLogEntryToAlertBatch(List<LogEntry> logEntries) {
|
||||
if (logEntries == null || logEntries.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (LogEntry logEntry : logEntries) {
|
||||
logEntryQueue.offer(logEntry);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LogEntry> pollLogEntryToAlertBatch(int maxBatchSize) throws InterruptedException {
|
||||
List<LogEntry> batch = new ArrayList<>(maxBatchSize);
|
||||
LogEntry first = logEntryQueue.poll(1, TimeUnit.SECONDS);
|
||||
if (first != null) {
|
||||
batch.add(first);
|
||||
logEntryQueue.drainTo(batch, maxBatchSize - 1);
|
||||
}
|
||||
return batch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendLogEntryToStorageBatch(List<LogEntry> logEntries) {
|
||||
if (logEntries == null || logEntries.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (LogEntry logEntry : logEntries) {
|
||||
logEntryToStorageQueue.offer(logEntry);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LogEntry> pollLogEntryToStorageBatch(int maxBatchSize) throws InterruptedException {
|
||||
List<LogEntry> batch = new ArrayList<>(maxBatchSize);
|
||||
LogEntry first = logEntryToStorageQueue.poll(1, TimeUnit.SECONDS);
|
||||
if (first != null) {
|
||||
batch.add(first);
|
||||
logEntryToStorageQueue.drainTo(batch, maxBatchSize - 1);
|
||||
}
|
||||
return batch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
metricsDataToAlertQueue.clear();
|
||||
metricsDataToStorageQueue.clear();
|
||||
serviceDiscoveryDataQueue.clear();
|
||||
logEntryQueue.clear();
|
||||
logEntryToStorageQueue.clear();
|
||||
}
|
||||
}
|
||||
+376
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
* 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.queue.impl;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.common.config.CommonProperties;
|
||||
import org.apache.hertzbeat.common.constants.DataQueueConstants;
|
||||
import org.apache.hertzbeat.common.entity.log.LogEntry;
|
||||
import org.apache.hertzbeat.common.entity.message.CollectRep;
|
||||
import org.apache.hertzbeat.common.queue.CommonDataQueue;
|
||||
import org.apache.hertzbeat.common.serialize.KafkaLogEntryDeserializer;
|
||||
import org.apache.hertzbeat.common.serialize.KafkaLogEntrySerializer;
|
||||
import org.apache.hertzbeat.common.serialize.KafkaMetricsDataDeserializer;
|
||||
import org.apache.hertzbeat.common.serialize.KafkaMetricsDataSerializer;
|
||||
import org.apache.hertzbeat.common.support.exception.CommonDataQueueUnknownException;
|
||||
import org.apache.kafka.clients.consumer.ConsumerConfig;
|
||||
import org.apache.kafka.clients.consumer.ConsumerRecord;
|
||||
import org.apache.kafka.clients.consumer.ConsumerRecords;
|
||||
import org.apache.kafka.clients.consumer.KafkaConsumer;
|
||||
import org.apache.kafka.clients.producer.KafkaProducer;
|
||||
import org.apache.kafka.clients.producer.ProducerConfig;
|
||||
import org.apache.kafka.clients.producer.ProducerRecord;
|
||||
import org.apache.kafka.common.serialization.LongDeserializer;
|
||||
import org.apache.kafka.common.serialization.LongSerializer;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
|
||||
/**
|
||||
* common data queue implement kafka
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(
|
||||
prefix = DataQueueConstants.PREFIX,
|
||||
name = DataQueueConstants.NAME,
|
||||
havingValue = DataQueueConstants.KAFKA
|
||||
)
|
||||
@Slf4j
|
||||
public class KafkaCommonDataQueue implements CommonDataQueue, DisposableBean {
|
||||
|
||||
private final ReentrantLock metricDataToAlertLock = new ReentrantLock();
|
||||
private final ReentrantLock metricDataToStorageLock = new ReentrantLock();
|
||||
private final ReentrantLock serviceDiscoveryDataLock = new ReentrantLock();
|
||||
private final ReentrantLock logEntryLock = new ReentrantLock();
|
||||
private final ReentrantLock logEntryToStorageLock = new ReentrantLock();
|
||||
private final LinkedBlockingQueue<CollectRep.MetricsData> metricsDataToAlertQueue;
|
||||
private final LinkedBlockingQueue<CollectRep.MetricsData> metricsDataToStorageQueue;
|
||||
private final LinkedBlockingQueue<CollectRep.MetricsData> serviceDiscoveryDataQueue;
|
||||
private final LinkedBlockingQueue<LogEntry> logEntryQueue;
|
||||
private final LinkedBlockingQueue<LogEntry> logEntryToStorageQueue;
|
||||
private final CommonProperties.KafkaProperties kafka;
|
||||
private KafkaProducer<Long, CollectRep.MetricsData> metricsDataProducer;
|
||||
private KafkaProducer<Long, LogEntry> logEntryProducer;
|
||||
private KafkaConsumer<Long, CollectRep.MetricsData> metricsDataToAlertConsumer;
|
||||
private KafkaConsumer<Long, CollectRep.MetricsData> metricsDataToStorageConsumer;
|
||||
private KafkaConsumer<Long, CollectRep.MetricsData> serviceDiscoveryDataConsumer;
|
||||
private KafkaConsumer<Long, LogEntry> logEntryConsumer;
|
||||
private KafkaConsumer<Long, LogEntry> logEntryToStorageConsumer;
|
||||
|
||||
public KafkaCommonDataQueue(CommonProperties properties) {
|
||||
if (properties == null || properties.getQueue() == null || properties.getQueue().getKafka() == null) {
|
||||
log.error("init error, please config common.queue.kafka props in application.yml");
|
||||
throw new IllegalArgumentException("please config common.queue.kafka props");
|
||||
}
|
||||
this.kafka = properties.getQueue().getKafka();
|
||||
metricsDataToAlertQueue = new LinkedBlockingQueue<>();
|
||||
metricsDataToStorageQueue = new LinkedBlockingQueue<>();
|
||||
serviceDiscoveryDataQueue = new LinkedBlockingQueue<>();
|
||||
logEntryQueue = new LinkedBlockingQueue<>();
|
||||
logEntryToStorageQueue = new LinkedBlockingQueue<>();
|
||||
initDataQueue();
|
||||
}
|
||||
|
||||
private void initDataQueue() {
|
||||
try {
|
||||
Map<String, Object> producerConfig = new HashMap<>(3);
|
||||
producerConfig.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafka.getServers());
|
||||
producerConfig.put(ProducerConfig.ACKS_CONFIG, "all");
|
||||
producerConfig.put(ProducerConfig.RETRIES_CONFIG, 3);
|
||||
metricsDataProducer = new KafkaProducer<>(producerConfig, new LongSerializer(), new KafkaMetricsDataSerializer());
|
||||
logEntryProducer = new KafkaProducer<>(producerConfig, new LongSerializer(), new KafkaLogEntrySerializer());
|
||||
|
||||
Map<String, Object> consumerConfig = new HashMap<>(4);
|
||||
consumerConfig.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, kafka.getServers());
|
||||
consumerConfig.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, "50");
|
||||
consumerConfig.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
|
||||
// 15 minute
|
||||
consumerConfig.put(ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG, "900000");
|
||||
consumerConfig.put("group.id", "default-consumer");
|
||||
|
||||
Map<String, Object> metricsToAlertConsumerConfig = new HashMap<>(consumerConfig);
|
||||
metricsToAlertConsumerConfig.put("group.id", "metrics-alert-consumer");
|
||||
metricsDataToAlertConsumer = new KafkaConsumer<>(metricsToAlertConsumerConfig, new LongDeserializer(), new KafkaMetricsDataDeserializer());
|
||||
metricsDataToAlertConsumer.subscribe(Collections.singletonList(kafka.getMetricsDataTopic()));
|
||||
|
||||
Map<String, Object> metricsToStorageConsumerConfig = new HashMap<>(consumerConfig);
|
||||
metricsToStorageConsumerConfig.put("group.id", "metrics-persistent-consumer");
|
||||
metricsDataToStorageConsumer = new KafkaConsumer<>(metricsToStorageConsumerConfig, new LongDeserializer(), new KafkaMetricsDataDeserializer());
|
||||
metricsDataToStorageConsumer.subscribe(Collections.singletonList(kafka.getMetricsDataToStorageTopic()));
|
||||
|
||||
Map<String, Object> serviceDiscoveryDataConsumerConfig = new HashMap<>(consumerConfig);
|
||||
serviceDiscoveryDataConsumerConfig.put("group.id", "service-discovery-data-consumer");
|
||||
serviceDiscoveryDataConsumer = new KafkaConsumer<>(serviceDiscoveryDataConsumerConfig, new LongDeserializer(),
|
||||
new KafkaMetricsDataDeserializer());
|
||||
serviceDiscoveryDataConsumer.subscribe(Collections.singletonList(kafka.getServiceDiscoveryDataTopic()));
|
||||
|
||||
Map<String, Object> logEntryConsumerConfig = new HashMap<>(consumerConfig);
|
||||
logEntryConsumerConfig.put("group.id", "log-entry-consumer");
|
||||
logEntryConsumer = new KafkaConsumer<>(logEntryConsumerConfig, new LongDeserializer(), new KafkaLogEntryDeserializer());
|
||||
logEntryConsumer.subscribe(Collections.singletonList(kafka.getLogEntryDataTopic()));
|
||||
|
||||
Map<String, Object> logEntryToStorageConsumerConfig = new HashMap<>(consumerConfig);
|
||||
logEntryToStorageConsumerConfig.put("group.id", "log-entry-storage-consumer");
|
||||
logEntryToStorageConsumer = new KafkaConsumer<>(logEntryToStorageConsumerConfig, new LongDeserializer(), new KafkaLogEntryDeserializer());
|
||||
logEntryToStorageConsumer.subscribe(Collections.singletonList(kafka.getLogEntryDataToStorageTopic()));
|
||||
} catch (Exception e) {
|
||||
log.error("please config common.queue.kafka props correctly", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectRep.MetricsData pollServiceDiscoveryData() throws InterruptedException {
|
||||
return genericPollDataFunction(serviceDiscoveryDataQueue, serviceDiscoveryDataConsumer, serviceDiscoveryDataLock);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectRep.MetricsData pollMetricsDataToAlerter() throws InterruptedException {
|
||||
return genericPollDataFunction(metricsDataToAlertQueue, metricsDataToAlertConsumer, metricDataToAlertLock);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectRep.MetricsData pollMetricsDataToStorage() throws InterruptedException {
|
||||
return genericPollDataFunction(metricsDataToStorageQueue, metricsDataToStorageConsumer, metricDataToStorageLock);
|
||||
}
|
||||
|
||||
public <T> T genericPollDataFunction(LinkedBlockingQueue<T> dataQueue, KafkaConsumer<Long, T> dataConsumer, ReentrantLock lock) throws InterruptedException {
|
||||
|
||||
T pollData = dataQueue.poll();
|
||||
if (pollData != null) {
|
||||
return pollData;
|
||||
}
|
||||
lock.lockInterruptibly();
|
||||
try {
|
||||
ConsumerRecords<Long, T> records = dataConsumer.poll(Duration.ofSeconds(1));
|
||||
int index = 0;
|
||||
for (ConsumerRecord<Long, T> record : records) {
|
||||
if (index == 0) {
|
||||
pollData = record.value();
|
||||
} else {
|
||||
dataQueue.offer(record.value());
|
||||
}
|
||||
index++;
|
||||
}
|
||||
dataConsumer.commitAsync();
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
throw new CommonDataQueueUnknownException(e.getMessage(), e);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return pollData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMetricsData(CollectRep.MetricsData metricsData) {
|
||||
if (metricsDataProducer != null) {
|
||||
ProducerRecord<Long, CollectRep.MetricsData> record =
|
||||
new ProducerRecord<>(kafka.getMetricsDataTopic(), metricsData);
|
||||
metricsDataProducer.send(record);
|
||||
} else {
|
||||
log.error("metricsDataProducer is not enabled");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMetricsDataToStorage(CollectRep.MetricsData metricsData) {
|
||||
if (metricsDataProducer != null) {
|
||||
ProducerRecord<Long, CollectRep.MetricsData> record =
|
||||
new ProducerRecord<>(kafka.getMetricsDataToStorageTopic(), metricsData);
|
||||
metricsDataProducer.send(record);
|
||||
} else {
|
||||
log.error("metricsDataProducer is not enabled");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendServiceDiscoveryData(CollectRep.MetricsData metricsData) {
|
||||
if (metricsDataProducer != null) {
|
||||
ProducerRecord<Long, CollectRep.MetricsData> record =
|
||||
new ProducerRecord<>(kafka.getServiceDiscoveryDataTopic(), metricsData);
|
||||
metricsDataProducer.send(record);
|
||||
} else {
|
||||
log.error("metricsDataProducer is not enabled");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendLogEntry(LogEntry logEntry) {
|
||||
if (logEntryProducer != null) {
|
||||
try {
|
||||
ProducerRecord<Long, LogEntry> record = new ProducerRecord<>(kafka.getLogEntryDataTopic(), logEntry);
|
||||
logEntryProducer.send(record);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to send LogEntry to Kafka: {}", e.getMessage());
|
||||
// Fallback to memory queue if Kafka fails
|
||||
logEntryQueue.offer(logEntry);
|
||||
}
|
||||
} else {
|
||||
log.warn("logEntryProducer is not enabled, using memory queue");
|
||||
logEntryQueue.offer(logEntry);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LogEntry pollLogEntry() throws InterruptedException {
|
||||
return genericPollDataFunction(logEntryQueue, logEntryConsumer, logEntryLock);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendLogEntryToStorage(LogEntry logEntry) {
|
||||
if (logEntryProducer != null) {
|
||||
try {
|
||||
ProducerRecord<Long, LogEntry> record = new ProducerRecord<>(kafka.getLogEntryDataToStorageTopic(), logEntry);
|
||||
logEntryProducer.send(record);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to send LogEntry to storage via Kafka: {}", e.getMessage());
|
||||
// Fallback to memory queue if Kafka fails
|
||||
logEntryToStorageQueue.offer(logEntry);
|
||||
}
|
||||
} else {
|
||||
log.warn("logEntryProducer is not enabled, using memory queue for storage");
|
||||
logEntryToStorageQueue.offer(logEntry);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LogEntry pollLogEntryToStorage() throws InterruptedException {
|
||||
return genericPollDataFunction(logEntryToStorageQueue, logEntryToStorageConsumer, logEntryToStorageLock);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendLogEntryToAlertBatch(List<LogEntry> logEntries) {
|
||||
if (logEntries == null || logEntries.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (logEntryProducer != null) {
|
||||
try {
|
||||
for (LogEntry logEntry : logEntries) {
|
||||
ProducerRecord<Long, LogEntry> record = new ProducerRecord<>(kafka.getLogEntryDataTopic(), logEntry);
|
||||
logEntryProducer.send(record);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to send LogEntry batch to Kafka: {}", e.getMessage());
|
||||
for (LogEntry logEntry : logEntries) {
|
||||
logEntryQueue.offer(logEntry);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.warn("logEntryProducer is not enabled, using memory queue");
|
||||
for (LogEntry logEntry : logEntries) {
|
||||
logEntryQueue.offer(logEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LogEntry> pollLogEntryToAlertBatch(int maxBatchSize) throws InterruptedException {
|
||||
return genericBatchPollDataFunction(logEntryQueue, logEntryConsumer, logEntryLock, maxBatchSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendLogEntryToStorageBatch(List<LogEntry> logEntries) {
|
||||
if (logEntries == null || logEntries.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (logEntryProducer != null) {
|
||||
try {
|
||||
for (LogEntry logEntry : logEntries) {
|
||||
ProducerRecord<Long, LogEntry> record = new ProducerRecord<>(kafka.getLogEntryDataToStorageTopic(), logEntry);
|
||||
logEntryProducer.send(record);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to send LogEntry batch to storage via Kafka: {}", e.getMessage());
|
||||
for (LogEntry logEntry : logEntries) {
|
||||
logEntryToStorageQueue.offer(logEntry);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.warn("logEntryProducer is not enabled, using memory queue for storage");
|
||||
for (LogEntry logEntry : logEntries) {
|
||||
logEntryToStorageQueue.offer(logEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LogEntry> pollLogEntryToStorageBatch(int maxBatchSize) throws InterruptedException {
|
||||
return genericBatchPollDataFunction(logEntryToStorageQueue, logEntryToStorageConsumer, logEntryToStorageLock, maxBatchSize);
|
||||
}
|
||||
|
||||
public <T> List<T> genericBatchPollDataFunction(LinkedBlockingQueue<T> dataQueue, KafkaConsumer<Long, T> dataConsumer,
|
||||
ReentrantLock lock, int maxBatchSize) throws InterruptedException {
|
||||
List<T> batch = new ArrayList<>(maxBatchSize);
|
||||
lock.lockInterruptibly();
|
||||
try {
|
||||
dataQueue.drainTo(batch, maxBatchSize);
|
||||
if (batch.size() >= maxBatchSize) {
|
||||
return batch;
|
||||
}
|
||||
ConsumerRecords<Long, T> records = dataConsumer.poll(Duration.ofSeconds(1));
|
||||
for (ConsumerRecord<Long, T> record : records) {
|
||||
if (batch.size() < maxBatchSize) {
|
||||
batch.add(record.value());
|
||||
} else {
|
||||
dataQueue.offer(record.value());
|
||||
}
|
||||
}
|
||||
dataConsumer.commitAsync();
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return batch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
if (metricsDataProducer != null) {
|
||||
metricsDataProducer.close();
|
||||
}
|
||||
if (metricsDataToAlertConsumer != null) {
|
||||
metricsDataToAlertConsumer.close();
|
||||
}
|
||||
if (metricsDataToStorageConsumer != null) {
|
||||
metricsDataToStorageConsumer.close();
|
||||
}
|
||||
if (serviceDiscoveryDataConsumer != null) {
|
||||
serviceDiscoveryDataConsumer.close();
|
||||
}
|
||||
if (logEntryProducer != null) {
|
||||
logEntryProducer.close();
|
||||
}
|
||||
if (logEntryConsumer != null) {
|
||||
logEntryConsumer.close();
|
||||
}
|
||||
if (logEntryToStorageConsumer != null) {
|
||||
logEntryToStorageConsumer.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
+242
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* 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.queue.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import io.lettuce.core.KeyValue;
|
||||
import io.lettuce.core.RedisClient;
|
||||
import io.lettuce.core.RedisURI;
|
||||
import io.lettuce.core.api.StatefulRedisConnection;
|
||||
import io.lettuce.core.api.sync.RedisCommands;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.common.config.CommonProperties;
|
||||
import org.apache.hertzbeat.common.constants.DataQueueConstants;
|
||||
import org.apache.hertzbeat.common.entity.log.LogEntry;
|
||||
import org.apache.hertzbeat.common.entity.message.CollectRep;
|
||||
import org.apache.hertzbeat.common.queue.CommonDataQueue;
|
||||
import org.apache.hertzbeat.common.serialize.RedisLogEntryCodec;
|
||||
import org.apache.hertzbeat.common.serialize.RedisMetricsDataCodec;
|
||||
import org.apache.hertzbeat.common.support.exception.CommonDataQueueUnknownException;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* common data queue implement redis.
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@ConditionalOnProperty(
|
||||
prefix = DataQueueConstants.PREFIX,
|
||||
name = DataQueueConstants.NAME,
|
||||
havingValue = DataQueueConstants.REDIS
|
||||
)
|
||||
public class RedisCommonDataQueue implements CommonDataQueue, DisposableBean {
|
||||
|
||||
private final RedisClient redisClient;
|
||||
private final StatefulRedisConnection<String, CollectRep.MetricsData> connection;
|
||||
private final RedisCommands<String, CollectRep.MetricsData> syncCommands;
|
||||
private final StatefulRedisConnection<String, LogEntry> logEntryConnection;
|
||||
private final RedisCommands<String, LogEntry> logEntrySyncCommands;
|
||||
private final String metricsDataQueueNameToStorage;
|
||||
private final String metricsDataQueueNameForServiceDiscovery;
|
||||
private final String metricsDataQueueNameToAlerter;
|
||||
private final String logEntryQueueName;
|
||||
private final String logEntryToStorageQueueName;
|
||||
private final CommonProperties.RedisProperties redisProperties;
|
||||
private final Long waitTimeout;
|
||||
|
||||
public RedisCommonDataQueue(CommonProperties properties) {
|
||||
|
||||
if (properties == null || properties.getQueue() == null || properties.getQueue().getRedis() == null) {
|
||||
log.error("init error, please config common.queue.redis props in application.yml");
|
||||
throw new IllegalArgumentException("please config common.queue.redis props");
|
||||
}
|
||||
|
||||
this.redisProperties = properties.getQueue().getRedis();
|
||||
|
||||
this.redisClient = RedisClient.create(
|
||||
RedisURI.builder()
|
||||
.withHost(redisProperties.getRedisHost())
|
||||
.withPort(redisProperties.getRedisPort())
|
||||
.build()
|
||||
);
|
||||
RedisMetricsDataCodec codec = new RedisMetricsDataCodec();
|
||||
this.connection = redisClient.connect(codec);
|
||||
this.syncCommands = connection.sync();
|
||||
RedisLogEntryCodec logCodec = new RedisLogEntryCodec();
|
||||
this.logEntryConnection = redisClient.connect(logCodec);
|
||||
this.logEntrySyncCommands = logEntryConnection.sync();
|
||||
this.metricsDataQueueNameToStorage = redisProperties.getMetricsDataQueueNameToPersistentStorage();
|
||||
this.metricsDataQueueNameForServiceDiscovery = redisProperties.getMetricsDataQueueNameForServiceDiscovery();
|
||||
this.metricsDataQueueNameToAlerter = redisProperties.getMetricsDataQueueNameToAlerter();
|
||||
this.logEntryQueueName = redisProperties.getLogEntryQueueName();
|
||||
this.logEntryToStorageQueueName = redisProperties.getLogEntryToStorageQueueName();
|
||||
this.waitTimeout = Objects.requireNonNullElse(redisProperties.getWaitTimeout(), 1L);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectRep.MetricsData pollMetricsDataToAlerter() throws InterruptedException {
|
||||
return genericBlockingPollFunction(metricsDataQueueNameToAlerter, syncCommands);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectRep.MetricsData pollMetricsDataToStorage() throws InterruptedException {
|
||||
return genericBlockingPollFunction(metricsDataQueueNameToStorage, syncCommands);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectRep.MetricsData pollServiceDiscoveryData() throws InterruptedException {
|
||||
return genericBlockingPollFunction(metricsDataQueueNameForServiceDiscovery, syncCommands);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMetricsData(CollectRep.MetricsData metricsData) {
|
||||
try {
|
||||
syncCommands.lpush(metricsDataQueueNameToAlerter, metricsData);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMetricsDataToStorage(CollectRep.MetricsData metricsData) {
|
||||
try {
|
||||
syncCommands.lpush(metricsDataQueueNameToStorage, metricsData);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendServiceDiscoveryData(CollectRep.MetricsData metricsData) {
|
||||
try {
|
||||
syncCommands.lpush(metricsDataQueueNameForServiceDiscovery, metricsData);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendLogEntry(LogEntry logEntry) {
|
||||
try {
|
||||
logEntrySyncCommands.lpush(logEntryQueueName, logEntry);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to send LogEntry to Redis: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LogEntry pollLogEntry() throws InterruptedException {
|
||||
return genericBlockingPollFunction(logEntryQueueName, logEntrySyncCommands);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendLogEntryToStorage(LogEntry logEntry) {
|
||||
try {
|
||||
logEntrySyncCommands.lpush(logEntryToStorageQueueName, logEntry);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to send LogEntry to storage via Redis: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LogEntry pollLogEntryToStorage() throws InterruptedException {
|
||||
return genericBlockingPollFunction(logEntryToStorageQueueName, logEntrySyncCommands);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void sendLogEntryToAlertBatch(List<LogEntry> logEntries) {
|
||||
if (logEntries == null || logEntries.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
logEntrySyncCommands.lpush(logEntryQueueName, logEntries.toArray(new LogEntry[0]));
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to send LogEntry batch to Redis: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LogEntry> pollLogEntryToAlertBatch(int maxBatchSize) throws InterruptedException {
|
||||
return genericBatchPollFunction(logEntryQueueName, logEntrySyncCommands, maxBatchSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void sendLogEntryToStorageBatch(List<LogEntry> logEntries) {
|
||||
if (logEntries == null || logEntries.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
logEntrySyncCommands.lpush(logEntryToStorageQueueName, logEntries.toArray(new LogEntry[0]));
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to send LogEntry batch to storage via Redis: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LogEntry> pollLogEntryToStorageBatch(int maxBatchSize) throws InterruptedException {
|
||||
return genericBatchPollFunction(logEntryToStorageQueueName, logEntrySyncCommands, maxBatchSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
connection.close();
|
||||
logEntryConnection.close();
|
||||
redisClient.shutdown();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private <T> T genericBlockingPollFunction(String key, RedisCommands<String, T> commands) throws InterruptedException {
|
||||
try {
|
||||
// Use BRPOP for blocking pop with the configured timeout.
|
||||
// If data arrives, it returns immediately; if it times out, it returns null.
|
||||
KeyValue<String, T> keyData = commands.brpop(waitTimeout, key);
|
||||
if (keyData != null) {
|
||||
return keyData.getValue();
|
||||
} else {
|
||||
// Returns null on timeout
|
||||
return null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Redis BRPOP failed: {}", e.getMessage());
|
||||
throw new CommonDataQueueUnknownException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private List<LogEntry> genericBatchPollFunction(String key, RedisCommands<String, LogEntry> commands, int maxBatchSize) {
|
||||
List<LogEntry> batch = new ArrayList<>(maxBatchSize);
|
||||
try {
|
||||
List<LogEntry> elements = commands.rpop(key, maxBatchSize);
|
||||
if (elements != null) {
|
||||
batch.addAll(elements);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Redis batch poll failed: {}", e.getMessage());
|
||||
}
|
||||
return batch;
|
||||
}
|
||||
|
||||
}
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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.support;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.common.concurrent.BackgroundTaskExecutor;
|
||||
import org.apache.hertzbeat.common.concurrent.ManagedExecutor;
|
||||
import org.apache.hertzbeat.common.concurrent.ManagedExecutors;
|
||||
import org.apache.hertzbeat.common.config.VirtualThreadProperties;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* common task worker thread pool
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class CommonThreadPool implements BackgroundTaskExecutor, DisposableBean {
|
||||
|
||||
private final ManagedExecutor workerExecutor;
|
||||
|
||||
private final ManagedExecutor longRunningExecutor;
|
||||
|
||||
public CommonThreadPool() {
|
||||
this(VirtualThreadProperties.defaults());
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public CommonThreadPool(VirtualThreadProperties virtualThreadProperties) {
|
||||
VirtualThreadProperties properties =
|
||||
virtualThreadProperties == null ? VirtualThreadProperties.defaults() : virtualThreadProperties;
|
||||
this.workerExecutor = createWorkerExecutor(properties);
|
||||
this.longRunningExecutor = createLongRunningExecutor(properties, workerExecutor);
|
||||
}
|
||||
|
||||
private ManagedExecutor createWorkerExecutor(VirtualThreadProperties properties) {
|
||||
Thread.UncaughtExceptionHandler handler = (thread, throwable) -> {
|
||||
log.error("common executor has uncaughtException.");
|
||||
log.error(throwable.getMessage(), throwable);
|
||||
};
|
||||
if (properties.enabled()) {
|
||||
VirtualThreadProperties.PoolProperties poolProperties = properties.common();
|
||||
return ManagedExecutors.newVirtualExecutor("common-worker", "common-worker-",
|
||||
poolProperties.mode(), poolProperties.maxConcurrentJobs(), handler);
|
||||
}
|
||||
return ManagedExecutors.wrap("common-worker", createLegacyExecutor(handler));
|
||||
}
|
||||
|
||||
private ManagedExecutor createLongRunningExecutor(VirtualThreadProperties properties, ManagedExecutor fallback) {
|
||||
if (!properties.enabled()) {
|
||||
return fallback;
|
||||
}
|
||||
return ManagedExecutors.newPlatformExecutor("common-long-running", "common-long-running-",
|
||||
(thread, throwable) -> {
|
||||
log.error("common longRunningExecutor has uncaughtException.");
|
||||
log.error(throwable.getMessage(), throwable);
|
||||
});
|
||||
}
|
||||
|
||||
private ExecutorService createLegacyExecutor(Thread.UncaughtExceptionHandler handler) {
|
||||
ThreadFactory threadFactory = new ThreadFactoryBuilder()
|
||||
.setUncaughtExceptionHandler(handler)
|
||||
.setDaemon(true)
|
||||
.setNameFormat("common-worker-%d")
|
||||
.build();
|
||||
return new ThreadPoolExecutor(1,
|
||||
Integer.MAX_VALUE,
|
||||
10,
|
||||
TimeUnit.SECONDS,
|
||||
new SynchronousQueue<>(),
|
||||
threadFactory,
|
||||
new ThreadPoolExecutor.AbortPolicy());
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the task thread
|
||||
* @param runnable Task
|
||||
* @throws RejectedExecutionException when thread pool full
|
||||
*/
|
||||
public void execute(Runnable runnable) throws RejectedExecutionException {
|
||||
workerExecutor.execute(runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a long-lived task outside of the short-task execution lane.
|
||||
*
|
||||
* @param runnable task
|
||||
*/
|
||||
public void executeLongRunning(Runnable runnable) {
|
||||
longRunningExecutor.execute(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
workerExecutor.close();
|
||||
if (longRunningExecutor != workerExecutor) {
|
||||
longRunningExecutor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.support;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Spring ApplicationContext Holder
|
||||
*/
|
||||
@Component
|
||||
public class SpringContextHolder implements ApplicationContextAware {
|
||||
|
||||
private static ApplicationContext applicationContext;
|
||||
|
||||
private static ConfigurableApplicationContext configurableApplicationContext;
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
|
||||
set(applicationContext);
|
||||
if (applicationContext instanceof ConfigurableApplicationContext context) {
|
||||
configurableApplicationContext = context;
|
||||
}
|
||||
}
|
||||
|
||||
private static void set(ApplicationContext applicationContext) {
|
||||
SpringContextHolder.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
public static ApplicationContext getApplicationContext() {
|
||||
assertApplicationContext();
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getBean(String beanName) {
|
||||
assertApplicationContext();
|
||||
return (T) applicationContext.getBean(beanName);
|
||||
}
|
||||
|
||||
public static <T> T getBean(Class<T> clazz) {
|
||||
assertApplicationContext();
|
||||
return (T) applicationContext.getBean(clazz);
|
||||
}
|
||||
|
||||
public static void shutdown() {
|
||||
assertApplicationContext();
|
||||
configurableApplicationContext.close();
|
||||
}
|
||||
|
||||
public static boolean isActive() {
|
||||
if (configurableApplicationContext == null) {
|
||||
return false;
|
||||
}
|
||||
return configurableApplicationContext.isActive();
|
||||
}
|
||||
|
||||
private static void assertApplicationContext() {
|
||||
if (null == applicationContext || null == configurableApplicationContext) {
|
||||
throw new RuntimeException("applicationContext is null, please inject the springContextHolder");
|
||||
}
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.support.event;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* Ai Provider configuration change event
|
||||
*/
|
||||
public class AiProviderConfigChangeEvent extends ApplicationEvent {
|
||||
|
||||
public AiProviderConfigChangeEvent(ApplicationContext source) {
|
||||
super(source);
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.support.event;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* the event for monitor delete
|
||||
*/
|
||||
public class MonitorDeletedEvent extends ApplicationEvent {
|
||||
|
||||
/**
|
||||
* monitoring id
|
||||
*/
|
||||
private final Long monitorId;
|
||||
|
||||
public MonitorDeletedEvent(Object source, Long monitorId) {
|
||||
super(source);
|
||||
this.monitorId = monitorId;
|
||||
}
|
||||
|
||||
public Long getMonitorId() {
|
||||
return monitorId;
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.support.event;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* the event for sms config change
|
||||
*/
|
||||
public class SmsConfigChangeEvent extends ApplicationEvent {
|
||||
|
||||
public SmsConfigChangeEvent(Object source) {
|
||||
super(source);
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.support.event;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* the event for system config change
|
||||
*/
|
||||
public class SystemConfigChangeEvent extends ApplicationEvent {
|
||||
|
||||
public SystemConfigChangeEvent(Object source) {
|
||||
super(source);
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.support.valid;
|
||||
|
||||
import jakarta.validation.ConstraintValidator;
|
||||
import jakarta.validation.ConstraintValidatorContext;
|
||||
import org.apache.hertzbeat.common.util.CommonUtil;
|
||||
|
||||
/**
|
||||
* email validator
|
||||
*/
|
||||
public class EmailParamValidator implements ConstraintValidator<EmailValid, String> {
|
||||
|
||||
@Override
|
||||
public boolean isValid(String value, ConstraintValidatorContext context) {
|
||||
// validate email
|
||||
return CommonUtil.validateEmail(value);
|
||||
}
|
||||
}
|
||||
+43
@@ -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.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.common.support.valid;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.ElementType.PARAMETER;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
import jakarta.validation.Constraint;
|
||||
import jakarta.validation.Payload;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* EmailValid
|
||||
*/
|
||||
@Target({ FIELD, PARAMETER })
|
||||
@Retention(RUNTIME)
|
||||
@Documented
|
||||
@Constraint(validatedBy = EmailParamValidator.class)
|
||||
public @interface EmailValid {
|
||||
|
||||
String message() default "Email value is invalid";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.support.valid;
|
||||
|
||||
import jakarta.validation.ConstraintValidator;
|
||||
import jakarta.validation.ConstraintValidatorContext;
|
||||
import org.apache.hertzbeat.common.util.IpDomainUtil;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Host Param Validator
|
||||
*/
|
||||
public class HostParamValidator implements ConstraintValidator<HostValid, String> {
|
||||
public static final String HTTP = "http://";
|
||||
public static final String HTTPS = "https://";
|
||||
public static final String BLANK = "";
|
||||
public static final String PATTERN_HTTP = "(?i)http://";
|
||||
public static final String PATTERN_HTTPS = "(?i)https://";
|
||||
|
||||
@Override
|
||||
public boolean isValid(String value, ConstraintValidatorContext context) {
|
||||
if (!StringUtils.hasText(value)) {
|
||||
return true;
|
||||
}
|
||||
if (value.toLowerCase().contains(HTTP)){
|
||||
value = value.replaceFirst(PATTERN_HTTP, BLANK);
|
||||
}
|
||||
if (value.toLowerCase().contains(HTTPS)){
|
||||
value = value.replaceFirst(PATTERN_HTTPS, BLANK);
|
||||
}
|
||||
|
||||
String hostPart = value;
|
||||
|
||||
if (value.contains(":")) {
|
||||
// if contains multiple ":", it may be IPv6 with port
|
||||
if (value.lastIndexOf(":") > value.indexOf(":") && value.contains("[")) {
|
||||
int portIndex = value.lastIndexOf(":");
|
||||
hostPart = value.substring(0, portIndex);
|
||||
} else if (value.split(":").length == 2) {
|
||||
// it is IPv4 or domain with port
|
||||
String[] parts = value.split(":");
|
||||
hostPart = parts[0];
|
||||
}
|
||||
}
|
||||
|
||||
return IpDomainUtil.validateIpDomain(hostPart);
|
||||
}
|
||||
|
||||
}
|
||||
+43
@@ -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.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.common.support.valid;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.ElementType.PARAMETER;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
import jakarta.validation.Constraint;
|
||||
import jakarta.validation.Payload;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Host Param Validator
|
||||
*/
|
||||
@Target({ FIELD, PARAMETER })
|
||||
@Retention(RUNTIME)
|
||||
@Documented
|
||||
@Constraint(validatedBy = HostParamValidator.class)
|
||||
public @interface HostValid {
|
||||
|
||||
String message() default "Host need ipv4,ipv6,hostname or domain,<br>EG:127.0.0.1 hertzbeat.com";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.support.valid;
|
||||
|
||||
import jakarta.validation.ConstraintValidator;
|
||||
import jakarta.validation.ConstraintValidatorContext;
|
||||
import org.apache.hertzbeat.common.util.CommonUtil;
|
||||
|
||||
/**
|
||||
* PhoneNum Param Validator
|
||||
*/
|
||||
public class PhoneNumParamValidator implements ConstraintValidator<PhoneNumValid, String> {
|
||||
|
||||
@Override
|
||||
public boolean isValid(String value, ConstraintValidatorContext context) {
|
||||
return CommonUtil.validatePhoneNum(value);
|
||||
}
|
||||
}
|
||||
+43
@@ -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.
|
||||
*/
|
||||
|
||||
package org.apache.hertzbeat.common.support.valid;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.ElementType.PARAMETER;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
import jakarta.validation.Constraint;
|
||||
import jakarta.validation.Payload;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* PhoneNum Param Validator
|
||||
*/
|
||||
@Target({ FIELD, PARAMETER })
|
||||
@Retention(RUNTIME)
|
||||
@Documented
|
||||
@Constraint(validatedBy = PhoneNumParamValidator.class)
|
||||
public @interface PhoneNumValid {
|
||||
|
||||
String message() default "Phone num value is invalid";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* 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.support.valid;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.JSQLParserException;
|
||||
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
|
||||
import net.sf.jsqlparser.statement.Statement;
|
||||
import net.sf.jsqlparser.statement.select.LateralSubSelect;
|
||||
import net.sf.jsqlparser.statement.select.ParenthesedSelect;
|
||||
import net.sf.jsqlparser.statement.select.Select;
|
||||
import net.sf.jsqlparser.statement.select.SetOperationList;
|
||||
import net.sf.jsqlparser.statement.select.WithItem;
|
||||
import net.sf.jsqlparser.util.TablesNamesFinder;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* SQL Security Validator using JSqlParser 5.1+.
|
||||
* Security Policy:
|
||||
* 1. Only SELECT statements are allowed.
|
||||
* 2. All referenced tables must be in the whitelist.
|
||||
* 3. Subqueries, UNION, CTE, LATERAL are blocked.
|
||||
*/
|
||||
@Slf4j
|
||||
public class SqlSecurityValidator {
|
||||
|
||||
private final Set<String> allowedTables;
|
||||
|
||||
public SqlSecurityValidator(Collection<String> allowedTables) {
|
||||
if (CollectionUtils.isEmpty(allowedTables)) {
|
||||
this.allowedTables = new HashSet<>();
|
||||
} else {
|
||||
this.allowedTables = allowedTables.stream()
|
||||
.map(this::normalizeIdentifier)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
|
||||
public void validate(String sql) throws SqlSecurityException {
|
||||
if (sql == null || sql.trim().isEmpty()) {
|
||||
throw new SqlSecurityException("SQL statement cannot be empty");
|
||||
}
|
||||
|
||||
Statement statement;
|
||||
try {
|
||||
statement = CCJSqlParserUtil.parse(sql);
|
||||
} catch (JSQLParserException e) {
|
||||
log.warn("Failed to parse SQL: {}", sql, e);
|
||||
throw new SqlSecurityException("Invalid SQL syntax: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
if (!(statement instanceof Select select)) {
|
||||
throw new SqlSecurityException("Only SELECT statements are allowed.");
|
||||
}
|
||||
|
||||
// Check for CTE at top level
|
||||
if (select.getWithItemsList() != null && !select.getWithItemsList().isEmpty()) {
|
||||
throw new SqlSecurityException("CTE (WITH clause) is not allowed");
|
||||
}
|
||||
|
||||
// Use custom TablesNamesFinder that throws on dangerous structures
|
||||
SecurityTablesNamesFinder finder = new SecurityTablesNamesFinder();
|
||||
List<String> tables;
|
||||
try {
|
||||
tables = finder.getTableList(statement);
|
||||
} catch (SecurityViolationException e) {
|
||||
throw new SqlSecurityException(e.getMessage());
|
||||
}
|
||||
|
||||
validateTables(tables);
|
||||
}
|
||||
|
||||
private void validateTables(List<String> tables) throws SqlSecurityException {
|
||||
if (CollectionUtils.isEmpty(tables)) {
|
||||
return;
|
||||
}
|
||||
if (allowedTables.isEmpty()) {
|
||||
throw new SqlSecurityException("No access allowed: whitelist is empty.");
|
||||
}
|
||||
|
||||
for (String table : tables) {
|
||||
String normalizedTable = normalizeIdentifier(table);
|
||||
if (!allowedTables.contains(normalizedTable)) {
|
||||
throw new SqlSecurityException("Access to table '" + table + "' is not allowed. "
|
||||
+ "Allowed tables: " + allowedTables);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String normalizeIdentifier(String identifier) {
|
||||
if (identifier == null) {
|
||||
return "";
|
||||
}
|
||||
return identifier.replace("\"", "").replace("`", "").replace("'", "").toLowerCase();
|
||||
}
|
||||
|
||||
private static class SecurityViolationException extends RuntimeException {
|
||||
SecurityViolationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom TablesNamesFinder that throws exceptions on dangerous SQL structures.
|
||||
* Extends TablesNamesFinder with proper generic type to avoid raw type warnings.
|
||||
*/
|
||||
private static class SecurityTablesNamesFinder extends TablesNamesFinder<Void> {
|
||||
|
||||
@Override
|
||||
public Void visit(ParenthesedSelect parenthesedSelect, Object context) {
|
||||
throw new SecurityViolationException("Subqueries are not allowed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(SetOperationList setOpList, Object context) {
|
||||
throw new SecurityViolationException("UNION and set operations are not allowed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(LateralSubSelect lateralSubSelect, Object context) {
|
||||
throw new SecurityViolationException("LATERAL subqueries are not allowed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(WithItem withItem, Object context) {
|
||||
throw new SecurityViolationException("CTE (WITH clause) is not allowed");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import java.util.Map;
|
||||
import org.apache.hertzbeat.common.constants.ExportFileConstants;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* File utils.
|
||||
*/
|
||||
|
||||
public final class FileUtil {
|
||||
|
||||
private FileUtil() {
|
||||
}
|
||||
|
||||
private static final Map<String, String> fileTypes;
|
||||
|
||||
static {
|
||||
fileTypes = Map.of(
|
||||
ExportFileConstants.JsonFile.FILE_SUFFIX, ExportFileConstants.JsonFile.TYPE,
|
||||
ExportFileConstants.YamlFile.FILE_SUFFIX, ExportFileConstants.YamlFile.TYPE,
|
||||
ExportFileConstants.ExcelFile.FILE_SUFFIX, ExportFileConstants.ExcelFile.TYPE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file name.
|
||||
* @param file {@link MultipartFile}
|
||||
* @return file name
|
||||
*/
|
||||
public static String getFileName(MultipartFile file) {
|
||||
|
||||
var fileName = file.getOriginalFilename();
|
||||
if (!StringUtils.hasText(fileName)) {
|
||||
return "";
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file type.
|
||||
* @param file {@link MultipartFile}
|
||||
* @return file type
|
||||
*/
|
||||
public static String getFileType(MultipartFile file) {
|
||||
|
||||
var fileName = getFileName(file);
|
||||
|
||||
if (!StringUtils.hasText(fileName)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
var dotIndex = fileName.lastIndexOf('.');
|
||||
if (dotIndex == -1 || dotIndex == fileName.length() - 1) {
|
||||
return "";
|
||||
}
|
||||
var fileNameExtension = fileName.substring(dotIndex);
|
||||
|
||||
return fileTypes.get(fileNameExtension);
|
||||
}
|
||||
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import javax.naming.AuthenticationException;
|
||||
|
||||
import org.apache.hertzbeat.common.constants.CommonConstants;
|
||||
import org.apache.hertzbeat.common.entity.dto.Message;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
/**
|
||||
* A tool which make the restful response be easy to use
|
||||
*/
|
||||
public class ResponseUtil {
|
||||
public static <T, E extends Exception> ResponseEntity<Message<T>> handle(Supplier<T, E> supplier) {
|
||||
try {
|
||||
T result = supplier.get();
|
||||
return ResponseEntity.ok(Message.success(result));
|
||||
} catch (Exception e) {
|
||||
byte err = CommonConstants.FAIL_CODE;
|
||||
if (e.getClass().equals(AuthenticationException.class)) {
|
||||
err = CommonConstants.LOGIN_FAILED_CODE;
|
||||
}
|
||||
return ResponseEntity.ok(Message.fail(err, e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
public static <T, E extends Exception> ResponseEntity<Message<T>> handle(Runnable runner) {
|
||||
try {
|
||||
runner.run();
|
||||
return ResponseEntity.ok(Message.success());
|
||||
} catch (Exception e) {
|
||||
byte err = CommonConstants.FAIL_CODE;
|
||||
if (e.getClass().equals(AuthenticationException.class)) {
|
||||
err = CommonConstants.LOGIN_FAILED_CODE;
|
||||
}
|
||||
return ResponseEntity.ok(Message.fail(err, e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Supplier interface for getting result
|
||||
*/
|
||||
public interface Supplier<T, E extends Exception> {
|
||||
|
||||
/**
|
||||
* Gets a result.
|
||||
*
|
||||
* @return a result
|
||||
*/
|
||||
T get() throws E;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runnable interface for running
|
||||
*/
|
||||
public interface Runnable {
|
||||
|
||||
/**
|
||||
* Run target method.
|
||||
*/
|
||||
void run() throws Exception;
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
# 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.
|
||||
|
||||
org.apache.hertzbeat.common.config.CommonConfig
|
||||
Vendored
+41
@@ -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.common.cache;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Test case for {@link CacheFactory}
|
||||
*/
|
||||
public class CacheFactoryTest {
|
||||
@Test
|
||||
void common() {
|
||||
CacheFactory.setNoticeCache(new LinkedList<>());
|
||||
CacheFactory.setAlertSilenceCache(new LinkedList<>());
|
||||
assertNotNull(CacheFactory.getAlertSilenceCache());
|
||||
assertNotNull(CacheFactory.getNoticeCache());
|
||||
CacheFactory.clearNoticeCache();
|
||||
CacheFactory.clearAlertSilenceCache();
|
||||
assertNull(CacheFactory.getAlertSilenceCache());
|
||||
assertNull(CacheFactory.getNoticeCache());
|
||||
}
|
||||
}
|
||||
Vendored
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.cache;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
import java.time.Duration;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Test case for {@link CaffeineCacheServiceImpl}
|
||||
*/
|
||||
class CaffeineCacheTest {
|
||||
private CommonCacheService<String, String> cacheService;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
cacheService = new CaffeineCacheServiceImpl<>(10, 100, Duration.ofMillis(3000), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCache() throws InterruptedException {
|
||||
String key = "key";
|
||||
String value = "value";
|
||||
|
||||
// test get & put
|
||||
cacheService.put(key, value);
|
||||
Assertions.assertEquals(value, cacheService.get(key));
|
||||
Assertions.assertTrue(cacheService.containsKey(key));
|
||||
|
||||
// test remove
|
||||
cacheService.remove(key);
|
||||
Assertions.assertNull(cacheService.get(key));
|
||||
|
||||
// test expire time
|
||||
cacheService.put(key, value);
|
||||
Thread.sleep(3000);
|
||||
Assertions.assertNull(cacheService.get(key));
|
||||
Assertions.assertNull(cacheService.get(key));
|
||||
|
||||
// test clear
|
||||
for (int i = 0; i < 10; i++) {
|
||||
cacheService.put(key + i, value);
|
||||
}
|
||||
cacheService.clear();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Assertions.assertNull(cacheService.get(key + i));
|
||||
}
|
||||
// test new method : cacheService.putAndGetOld(key,newValue)
|
||||
String oldValue = "oldOne";
|
||||
String newValue = "newOne";
|
||||
cacheService.put(key, oldValue);
|
||||
Assertions.assertEquals(oldValue, cacheService.putAndGetOld(key, newValue));
|
||||
Assertions.assertEquals(newValue, cacheService.get(key));
|
||||
}
|
||||
|
||||
@Test
|
||||
void weekCache() {
|
||||
CommonCacheService<String, String> cache = new CaffeineCacheServiceImpl<>(10, 100, Duration.ofMillis(3000), true);
|
||||
assertNotNull(cache);
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.config;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.apache.hertzbeat.common.entity.dto.sms.SmsConfig;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
class SmsConfigBindingTest {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withUserConfiguration(BindingConfig.class);
|
||||
|
||||
@Test
|
||||
void bindsRuntimeSmsConfigWithoutSpringAnnotationsOnModel() {
|
||||
contextRunner.withPropertyValues(
|
||||
"alerter.sms.enable=true",
|
||||
"alerter.sms.type=smslocal",
|
||||
"alerter.sms.smslocal.api-key=test-key")
|
||||
.run(context -> {
|
||||
SmsConfig smsConfig = context.getBean(SmsConfig.class);
|
||||
assertTrue(smsConfig.isEnable());
|
||||
assertEquals("smslocal", smsConfig.getType());
|
||||
assertEquals("test-key", smsConfig.getSmslocal().getApiKey());
|
||||
});
|
||||
}
|
||||
|
||||
@EnableConfigurationProperties(SmsConfigBinding.class)
|
||||
static class BindingConfig {
|
||||
}
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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.config;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.apache.hertzbeat.common.concurrent.AdmissionMode;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
class VirtualThreadPropertiesTest {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withUserConfiguration(BindingConfig.class);
|
||||
|
||||
@Test
|
||||
void defaultsRemainSafeWithoutExternalConfiguration() {
|
||||
VirtualThreadProperties properties = VirtualThreadProperties.defaults();
|
||||
|
||||
assertTrue(properties.enabled());
|
||||
|
||||
assertEquals(AdmissionMode.LIMIT_AND_REJECT, properties.collector().mode());
|
||||
assertEquals(512, properties.collector().maxConcurrentJobs());
|
||||
|
||||
assertEquals(AdmissionMode.UNBOUNDED_VT, properties.common().mode());
|
||||
assertEquals(AdmissionMode.LIMIT_AND_REJECT, properties.manager().mode());
|
||||
assertEquals(10, properties.manager().maxConcurrentJobs());
|
||||
|
||||
assertEquals(AdmissionMode.LIMIT_AND_REJECT, properties.alerter().notifyPool().mode());
|
||||
assertEquals(64, properties.alerter().notifyPool().maxConcurrentJobs());
|
||||
assertEquals(10, properties.alerter().periodicMaxConcurrentJobs());
|
||||
assertEquals(10, properties.alerter().logWorker().maxConcurrentJobs());
|
||||
assertEquals(1000, properties.alerter().logWorker().queueCapacity());
|
||||
assertEquals(2, properties.alerter().reduce().maxConcurrentJobs());
|
||||
assertEquals(0, properties.alerter().reduce().queueCapacity());
|
||||
assertEquals(2, properties.alerter().windowEvaluator().maxConcurrentJobs());
|
||||
assertEquals(0, properties.alerter().windowEvaluator().queueCapacity());
|
||||
assertEquals(4, properties.alerter().notifyMaxConcurrentPerChannel());
|
||||
|
||||
assertEquals(AdmissionMode.UNBOUNDED_VT, properties.warehouse().mode());
|
||||
|
||||
assertTrue(properties.async().enabled());
|
||||
assertEquals(256, properties.async().concurrencyLimit());
|
||||
assertTrue(properties.async().rejectWhenLimitReached());
|
||||
assertEquals(5000L, properties.async().taskTerminationTimeout());
|
||||
}
|
||||
|
||||
@Test
|
||||
void collectorModeOnlyBindingRetainsDefaultConcurrency() {
|
||||
contextRunner.withPropertyValues("hertzbeat.vthreads.collector.mode=LIMIT_AND_REJECT")
|
||||
.run(context -> {
|
||||
VirtualThreadProperties properties = context.getBean(VirtualThreadProperties.class);
|
||||
assertEquals(AdmissionMode.LIMIT_AND_REJECT, properties.collector().mode());
|
||||
assertEquals(512, properties.collector().maxConcurrentJobs());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void collectorModeOverrideUsesConfiguredMode() {
|
||||
contextRunner.withPropertyValues("hertzbeat.vthreads.collector.mode=LIMIT_AND_BLOCK")
|
||||
.run(context -> {
|
||||
VirtualThreadProperties properties = context.getBean(VirtualThreadProperties.class);
|
||||
assertEquals(AdmissionMode.LIMIT_AND_BLOCK, properties.collector().mode());
|
||||
assertEquals(512, properties.collector().maxConcurrentJobs());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void notifyModeOnlyBindingRetainsDefaultConcurrency() {
|
||||
contextRunner.withPropertyValues("hertzbeat.vthreads.alerter.notify.mode=LIMIT_AND_BLOCK")
|
||||
.run(context -> {
|
||||
VirtualThreadProperties properties = context.getBean(VirtualThreadProperties.class);
|
||||
assertEquals(AdmissionMode.LIMIT_AND_BLOCK, properties.alerter().notifyPool().mode());
|
||||
assertEquals(64, properties.alerter().notifyPool().maxConcurrentJobs());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void logWorkerQueueOnlyBindingRetainsDefaultConcurrency() {
|
||||
contextRunner.withPropertyValues("hertzbeat.vthreads.alerter.log-worker.queue-capacity=32")
|
||||
.run(context -> {
|
||||
VirtualThreadProperties properties = context.getBean(VirtualThreadProperties.class);
|
||||
assertEquals(10, properties.alerter().logWorker().maxConcurrentJobs());
|
||||
assertEquals(32, properties.alerter().logWorker().queueCapacity());
|
||||
});
|
||||
}
|
||||
|
||||
@EnableConfigurationProperties(VirtualThreadPropertiesBinding.class)
|
||||
static class BindingConfig {
|
||||
|
||||
@Bean
|
||||
VirtualThreadProperties virtualThreadProperties(VirtualThreadPropertiesBinding binding) {
|
||||
return binding.toRuntimeProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
+323
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import jakarta.validation.ConstraintViolation;
|
||||
import jakarta.validation.Validation;
|
||||
import jakarta.validation.Validator;
|
||||
import jakarta.validation.ValidatorFactory;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Test case for {@link MetricsFavorite}
|
||||
*/
|
||||
class MetricsFavoriteTest {
|
||||
|
||||
private final ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
|
||||
private final Validator validator = factory.getValidator();
|
||||
|
||||
@Test
|
||||
void testBuilder() {
|
||||
String creator = "testUser";
|
||||
Long monitorId = 1L;
|
||||
String metricsName = "cpu";
|
||||
LocalDateTime createTime = LocalDateTime.now();
|
||||
|
||||
MetricsFavorite favorite = MetricsFavorite.builder()
|
||||
.id(1L)
|
||||
.creator(creator)
|
||||
.monitorId(monitorId)
|
||||
.metricsName(metricsName)
|
||||
.createTime(createTime)
|
||||
.build();
|
||||
|
||||
assertNotNull(favorite);
|
||||
assertEquals(1L, favorite.getId());
|
||||
assertEquals(creator, favorite.getCreator());
|
||||
assertEquals(monitorId, favorite.getMonitorId());
|
||||
assertEquals(metricsName, favorite.getMetricsName());
|
||||
assertEquals(createTime, favorite.getCreateTime());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBuilderWithoutOptionalFields() {
|
||||
String creator = "testUser";
|
||||
Long monitorId = 1L;
|
||||
String metricsName = "cpu";
|
||||
|
||||
MetricsFavorite favorite = MetricsFavorite.builder()
|
||||
.creator(creator)
|
||||
.monitorId(monitorId)
|
||||
.metricsName(metricsName)
|
||||
.build();
|
||||
|
||||
assertNotNull(favorite);
|
||||
assertNull(favorite.getId());
|
||||
assertEquals(creator, favorite.getCreator());
|
||||
assertEquals(monitorId, favorite.getMonitorId());
|
||||
assertEquals(metricsName, favorite.getMetricsName());
|
||||
assertNull(favorite.getCreateTime());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDefaultConstructor() {
|
||||
MetricsFavorite favorite = new MetricsFavorite();
|
||||
|
||||
assertNotNull(favorite);
|
||||
assertNull(favorite.getId());
|
||||
assertNull(favorite.getCreator());
|
||||
assertNull(favorite.getMonitorId());
|
||||
assertNull(favorite.getMetricsName());
|
||||
assertNull(favorite.getCreateTime());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSettersAndGetters() {
|
||||
MetricsFavorite favorite = new MetricsFavorite();
|
||||
String creator = "testUser";
|
||||
Long monitorId = 1L;
|
||||
String metricsName = "cpu";
|
||||
LocalDateTime createTime = LocalDateTime.now();
|
||||
|
||||
favorite.setId(1L);
|
||||
favorite.setCreator(creator);
|
||||
favorite.setMonitorId(monitorId);
|
||||
favorite.setMetricsName(metricsName);
|
||||
favorite.setCreateTime(createTime);
|
||||
|
||||
assertEquals(1L, favorite.getId());
|
||||
assertEquals(creator, favorite.getCreator());
|
||||
assertEquals(monitorId, favorite.getMonitorId());
|
||||
assertEquals(metricsName, favorite.getMetricsName());
|
||||
assertEquals(createTime, favorite.getCreateTime());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidation_ValidEntity() {
|
||||
MetricsFavorite favorite = MetricsFavorite.builder()
|
||||
.creator("testUser")
|
||||
.monitorId(1L)
|
||||
.metricsName("cpu")
|
||||
.createTime(LocalDateTime.now())
|
||||
.build();
|
||||
|
||||
Set<ConstraintViolation<MetricsFavorite>> violations = validator.validate(favorite);
|
||||
|
||||
assertTrue(violations.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidation_NullCreator() {
|
||||
MetricsFavorite favorite = MetricsFavorite.builder()
|
||||
.creator(null)
|
||||
.monitorId(1L)
|
||||
.metricsName("cpu")
|
||||
.createTime(LocalDateTime.now())
|
||||
.build();
|
||||
|
||||
Set<ConstraintViolation<MetricsFavorite>> violations = validator.validate(favorite);
|
||||
|
||||
assertFalse(violations.isEmpty());
|
||||
assertTrue(violations.stream().anyMatch(v -> v.getPropertyPath().toString().equals("creator")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidation_BlankCreator() {
|
||||
MetricsFavorite favorite = MetricsFavorite.builder()
|
||||
.creator(" ")
|
||||
.monitorId(1L)
|
||||
.metricsName("cpu")
|
||||
.createTime(LocalDateTime.now())
|
||||
.build();
|
||||
|
||||
Set<ConstraintViolation<MetricsFavorite>> violations = validator.validate(favorite);
|
||||
|
||||
assertFalse(violations.isEmpty());
|
||||
assertTrue(violations.stream().anyMatch(v -> v.getPropertyPath().toString().equals("creator")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidation_CreatorTooLong() {
|
||||
String longCreator = "a".repeat(256);
|
||||
MetricsFavorite favorite = MetricsFavorite.builder()
|
||||
.creator(longCreator)
|
||||
.monitorId(1L)
|
||||
.metricsName("cpu")
|
||||
.createTime(LocalDateTime.now())
|
||||
.build();
|
||||
|
||||
Set<ConstraintViolation<MetricsFavorite>> violations = validator.validate(favorite);
|
||||
|
||||
assertFalse(violations.isEmpty());
|
||||
assertTrue(violations.stream().anyMatch(v -> v.getPropertyPath().toString().equals("creator")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidation_NullMonitorId() {
|
||||
MetricsFavorite favorite = MetricsFavorite.builder()
|
||||
.creator("testUser")
|
||||
.monitorId(null)
|
||||
.metricsName("cpu")
|
||||
.createTime(LocalDateTime.now())
|
||||
.build();
|
||||
|
||||
Set<ConstraintViolation<MetricsFavorite>> violations = validator.validate(favorite);
|
||||
|
||||
assertFalse(violations.isEmpty());
|
||||
assertTrue(violations.stream().anyMatch(v -> v.getPropertyPath().toString().equals("monitorId")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidation_NullMetricsName() {
|
||||
MetricsFavorite favorite = MetricsFavorite.builder()
|
||||
.creator("testUser")
|
||||
.monitorId(1L)
|
||||
.metricsName(null)
|
||||
.createTime(LocalDateTime.now())
|
||||
.build();
|
||||
|
||||
Set<ConstraintViolation<MetricsFavorite>> violations = validator.validate(favorite);
|
||||
|
||||
assertFalse(violations.isEmpty());
|
||||
assertTrue(violations.stream().anyMatch(v -> v.getPropertyPath().toString().equals("metricsName")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidation_BlankMetricsName() {
|
||||
MetricsFavorite favorite = MetricsFavorite.builder()
|
||||
.creator("testUser")
|
||||
.monitorId(1L)
|
||||
.metricsName(" ")
|
||||
.createTime(LocalDateTime.now())
|
||||
.build();
|
||||
|
||||
Set<ConstraintViolation<MetricsFavorite>> violations = validator.validate(favorite);
|
||||
|
||||
assertFalse(violations.isEmpty());
|
||||
assertTrue(violations.stream().anyMatch(v -> v.getPropertyPath().toString().equals("metricsName")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidation_MetricsNameTooLong() {
|
||||
String longMetricsName = "a".repeat(256);
|
||||
MetricsFavorite favorite = MetricsFavorite.builder()
|
||||
.creator("testUser")
|
||||
.monitorId(1L)
|
||||
.metricsName(longMetricsName)
|
||||
.createTime(LocalDateTime.now())
|
||||
.build();
|
||||
|
||||
Set<ConstraintViolation<MetricsFavorite>> violations = validator.validate(favorite);
|
||||
|
||||
assertFalse(violations.isEmpty());
|
||||
assertTrue(violations.stream().anyMatch(v -> v.getPropertyPath().toString().equals("metricsName")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEqualsAndHashCode() {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
MetricsFavorite favorite1 = MetricsFavorite.builder()
|
||||
.id(1L)
|
||||
.creator("testUser")
|
||||
.monitorId(1L)
|
||||
.metricsName("cpu")
|
||||
.createTime(now)
|
||||
.build();
|
||||
|
||||
MetricsFavorite favorite2 = MetricsFavorite.builder()
|
||||
.id(1L)
|
||||
.creator("testUser")
|
||||
.monitorId(1L)
|
||||
.metricsName("cpu")
|
||||
.createTime(now)
|
||||
.build();
|
||||
|
||||
MetricsFavorite favorite3 = MetricsFavorite.builder()
|
||||
.id(2L)
|
||||
.creator("testUser")
|
||||
.monitorId(1L)
|
||||
.metricsName("cpu")
|
||||
.createTime(now)
|
||||
.build();
|
||||
|
||||
assertEquals(favorite1, favorite2);
|
||||
assertEquals(favorite1.hashCode(), favorite2.hashCode());
|
||||
assertNotEquals(favorite1, favorite3);
|
||||
assertNotEquals(favorite1.hashCode(), favorite3.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testToString() {
|
||||
MetricsFavorite favorite = MetricsFavorite.builder()
|
||||
.id(1L)
|
||||
.creator("testUser")
|
||||
.monitorId(1L)
|
||||
.metricsName("cpu")
|
||||
.createTime(LocalDateTime.now())
|
||||
.build();
|
||||
|
||||
String toString = favorite.toString();
|
||||
|
||||
assertNotNull(toString);
|
||||
assertTrue(toString.contains("MetricsFavorite"));
|
||||
assertTrue(toString.contains("testUser"));
|
||||
assertTrue(toString.contains("cpu"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreatorMaxLength() {
|
||||
String maxLengthCreator = "a".repeat(255);
|
||||
MetricsFavorite favorite = MetricsFavorite.builder()
|
||||
.creator(maxLengthCreator)
|
||||
.monitorId(1L)
|
||||
.metricsName("cpu")
|
||||
.createTime(LocalDateTime.now())
|
||||
.build();
|
||||
|
||||
Set<ConstraintViolation<MetricsFavorite>> violations = validator.validate(favorite);
|
||||
|
||||
assertTrue(violations.isEmpty());
|
||||
assertEquals(255, favorite.getCreator().length());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMetricsNameMaxLength() {
|
||||
String maxLengthMetricsName = "a".repeat(255);
|
||||
MetricsFavorite favorite = MetricsFavorite.builder()
|
||||
.creator("testUser")
|
||||
.monitorId(1L)
|
||||
.metricsName(maxLengthMetricsName)
|
||||
.createTime(LocalDateTime.now())
|
||||
.build();
|
||||
|
||||
Set<ConstraintViolation<MetricsFavorite>> violations = validator.validate(favorite);
|
||||
|
||||
assertTrue(violations.isEmpty());
|
||||
assertEquals(255, favorite.getMetricsName().length());
|
||||
}
|
||||
}
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* 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.queue.impl;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import java.time.Instant;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.hertzbeat.common.entity.log.LogEntry;
|
||||
import org.apache.hertzbeat.common.entity.message.CollectRep;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Test case for {@link InMemoryCommonDataQueue}
|
||||
*/
|
||||
class InMemoryCommonDataQueueTest {
|
||||
|
||||
private InMemoryCommonDataQueue queue;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
queue = new InMemoryCommonDataQueue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMetricsData() throws InterruptedException {
|
||||
|
||||
var metricsData = CollectRep.MetricsData.newBuilder().build();
|
||||
|
||||
queue.sendMetricsData(metricsData);
|
||||
|
||||
CollectRep.MetricsData polledMetricsData = queue.pollMetricsDataToAlerter();
|
||||
|
||||
assertNotNull(polledMetricsData);
|
||||
assertEquals(metricsData, polledMetricsData);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLogEntry() throws InterruptedException {
|
||||
|
||||
// Create a test log entry with comprehensive data
|
||||
Map<String, Object> attributes = new HashMap<>();
|
||||
attributes.put("service.name", "hertzbeat");
|
||||
attributes.put("service.version", "1.0.0");
|
||||
|
||||
Map<String, Object> resource = new HashMap<>();
|
||||
resource.put("host.name", "localhost");
|
||||
resource.put("os.type", "linux");
|
||||
|
||||
LogEntry.InstrumentationScope scope = LogEntry.InstrumentationScope.builder()
|
||||
.name("org.apache.hertzbeat.test")
|
||||
.version("1.0.0")
|
||||
.build();
|
||||
|
||||
LogEntry logEntry = LogEntry.builder()
|
||||
.timeUnixNano(Instant.now().toEpochMilli() * 1_000_000L)
|
||||
.observedTimeUnixNano(Instant.now().toEpochMilli() * 1_000_000L)
|
||||
.severityNumber(9) // INFO level
|
||||
.severityText("INFO")
|
||||
.body("Test log message for hertzbeat queue")
|
||||
.attributes(attributes)
|
||||
.resource(resource)
|
||||
.instrumentationScope(scope)
|
||||
.traceId("1234567890abcdef1234567890abcdef")
|
||||
.spanId("1234567890abcdef")
|
||||
.traceFlags(1)
|
||||
.build();
|
||||
|
||||
// Test sending and polling log entry
|
||||
queue.sendLogEntry(logEntry);
|
||||
|
||||
LogEntry polledLogEntry = queue.pollLogEntry();
|
||||
|
||||
assertNotNull(polledLogEntry);
|
||||
assertEquals(logEntry.getSeverityText(), polledLogEntry.getSeverityText());
|
||||
assertEquals(logEntry.getBody(), polledLogEntry.getBody());
|
||||
assertEquals(logEntry.getTraceId(), polledLogEntry.getTraceId());
|
||||
assertEquals(logEntry.getSpanId(), polledLogEntry.getSpanId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLogEntryToStorage() throws InterruptedException {
|
||||
|
||||
// Create a simple log entry for storage test
|
||||
LogEntry logEntry = LogEntry.builder()
|
||||
.timeUnixNano(Instant.now().toEpochMilli() * 1_000_000L)
|
||||
.severityNumber(17) // ERROR level
|
||||
.severityText("ERROR")
|
||||
.body("Error log message for storage")
|
||||
.build();
|
||||
|
||||
// Test sending and polling log entry to storage
|
||||
queue.sendLogEntryToStorage(logEntry);
|
||||
|
||||
LogEntry polledLogEntry = queue.pollLogEntryToStorage();
|
||||
|
||||
assertNotNull(polledLogEntry);
|
||||
assertEquals(logEntry.getSeverityText(), polledLogEntry.getSeverityText());
|
||||
assertEquals(logEntry.getBody(), polledLogEntry.getBody());
|
||||
assertEquals(logEntry.getSeverityNumber(), polledLogEntry.getSeverityNumber());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetQueueSizeMetricsInfo() {
|
||||
|
||||
Map<String, Integer> metricsInfo = queue.getQueueSizeMetricsInfo();
|
||||
|
||||
assertEquals(0, metricsInfo.get("metricsDataToAlertQueue"));
|
||||
assertEquals(0, metricsInfo.get("metricsDataToStorageQueue"));
|
||||
assertEquals(0, metricsInfo.get("logEntryQueue"));
|
||||
assertEquals(0, metricsInfo.get("logEntryToStorageQueue"));
|
||||
|
||||
// Add metrics data and log entries
|
||||
queue.sendMetricsData(CollectRep.MetricsData.newBuilder().build());
|
||||
queue.sendLogEntry(LogEntry.builder().body("Test log").build());
|
||||
queue.sendLogEntryToStorage(LogEntry.builder().body("Storage log").build());
|
||||
|
||||
metricsInfo = queue.getQueueSizeMetricsInfo();
|
||||
|
||||
assertEquals(1, metricsInfo.get("metricsDataToAlertQueue"));
|
||||
assertEquals(0, metricsInfo.get("metricsDataToStorageQueue"));
|
||||
assertEquals(1, metricsInfo.get("logEntryQueue"));
|
||||
assertEquals(1, metricsInfo.get("logEntryToStorageQueue"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDestroy() {
|
||||
|
||||
// Add both metrics data and log entries before destroy
|
||||
queue.sendMetricsData(CollectRep.MetricsData.newBuilder().build());
|
||||
queue.sendLogEntry(LogEntry.builder().body("Test log").build());
|
||||
queue.sendLogEntryToStorage(LogEntry.builder().body("Storage log").build());
|
||||
|
||||
queue.destroy();
|
||||
|
||||
Map<String, Integer> metricsInfo = queue.getQueueSizeMetricsInfo();
|
||||
|
||||
assertEquals(0, metricsInfo.get("metricsDataToAlertQueue"));
|
||||
assertEquals(0, metricsInfo.get("metricsDataToStorageQueue"));
|
||||
assertEquals(0, metricsInfo.get("logEntryQueue"));
|
||||
assertEquals(0, metricsInfo.get("logEntryToStorageQueue"));
|
||||
}
|
||||
|
||||
}
|
||||
+260
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* 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.queue.impl;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.anyCollection;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.withSettings;
|
||||
import java.lang.reflect.Field;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.hertzbeat.common.config.CommonProperties;
|
||||
import org.apache.hertzbeat.common.entity.log.LogEntry;
|
||||
import org.apache.hertzbeat.common.entity.message.CollectRep;
|
||||
import org.apache.kafka.clients.consumer.ConsumerRecord;
|
||||
import org.apache.kafka.clients.consumer.ConsumerRecords;
|
||||
import org.apache.kafka.clients.consumer.KafkaConsumer;
|
||||
import org.apache.kafka.clients.producer.KafkaProducer;
|
||||
import org.apache.kafka.common.TopicPartition;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
/**
|
||||
* Test case for {@link KafkaCommonDataQueue}
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class KafkaCommonDataQueueTest {
|
||||
|
||||
@Mock(lenient = true)
|
||||
private KafkaConsumer<Long, CollectRep.MetricsData> metricsDataToAlertConsumer;
|
||||
|
||||
@Mock(lenient = true)
|
||||
private KafkaProducer<Long, CollectRep.MetricsData> metricsDataProducer;
|
||||
|
||||
@Mock(lenient = true)
|
||||
private KafkaProducer<Long, LogEntry> logEntryProducer;
|
||||
|
||||
@Mock(lenient = true)
|
||||
private KafkaConsumer<Long, LogEntry> logEntryConsumer;
|
||||
|
||||
@Mock(lenient = true)
|
||||
private KafkaConsumer<Long, LogEntry> logEntryToStorageConsumer;
|
||||
|
||||
private KafkaCommonDataQueue kafkaCommonDataQueue;
|
||||
|
||||
private CommonProperties commonProperties;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws Exception {
|
||||
commonProperties = mock(CommonProperties.class);
|
||||
CommonProperties.DataQueueProperties dataQueueProperties = mock(CommonProperties.DataQueueProperties.class, withSettings().lenient());
|
||||
CommonProperties.KafkaProperties kafkaProperties = mock(CommonProperties.KafkaProperties.class, withSettings().lenient());
|
||||
|
||||
when(commonProperties.getQueue()).thenReturn(dataQueueProperties);
|
||||
when(dataQueueProperties.getKafka()).thenReturn(kafkaProperties);
|
||||
|
||||
// Set all required topics
|
||||
when(kafkaProperties.getMetricsDataTopic()).thenReturn("metricsDataTopic");
|
||||
when(kafkaProperties.getLogEntryDataTopic()).thenReturn("logEntryDataTopic");
|
||||
when(kafkaProperties.getLogEntryDataToStorageTopic()).thenReturn("logEntryDataToStorageTopic");
|
||||
when(kafkaProperties.getAlertsDataTopic()).thenReturn("alertsDataTopic");
|
||||
when(kafkaProperties.getMetricsDataToStorageTopic()).thenReturn("metricsDataToStorageTopic");
|
||||
when(kafkaProperties.getServiceDiscoveryDataTopic()).thenReturn("serviceDiscoveryDataTopic");
|
||||
when(kafkaProperties.getServers()).thenReturn("localhost:9092");
|
||||
|
||||
// Simulate the subscribe method for consumers
|
||||
doNothing().when(metricsDataToAlertConsumer).subscribe(anyCollection());
|
||||
doNothing().when(logEntryConsumer).subscribe(anyCollection());
|
||||
doNothing().when(logEntryToStorageConsumer).subscribe(anyCollection());
|
||||
|
||||
kafkaCommonDataQueue = new KafkaCommonDataQueue(commonProperties);
|
||||
|
||||
// Use reflection to set private fields
|
||||
setPrivateField(kafkaCommonDataQueue, "metricsDataProducer", metricsDataProducer);
|
||||
setPrivateField(kafkaCommonDataQueue, "metricsDataToAlertConsumer", metricsDataToAlertConsumer);
|
||||
setPrivateField(kafkaCommonDataQueue, "logEntryProducer", logEntryProducer);
|
||||
setPrivateField(kafkaCommonDataQueue, "logEntryConsumer", logEntryConsumer);
|
||||
setPrivateField(kafkaCommonDataQueue, "logEntryToStorageConsumer", logEntryToStorageConsumer);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSendMetricsData() {
|
||||
CollectRep.MetricsData metricsData = CollectRep.MetricsData.newBuilder()
|
||||
.setMetrics("test metrics")
|
||||
.build();
|
||||
|
||||
kafkaCommonDataQueue.sendMetricsData(metricsData);
|
||||
|
||||
verify(metricsDataProducer).send(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPollMetricsDataToAlerter() throws InterruptedException {
|
||||
// Create a test data
|
||||
CollectRep.MetricsData expectedData = CollectRep.MetricsData.newBuilder()
|
||||
.setMetrics("test metrics")
|
||||
.build();
|
||||
|
||||
// Create a ConsumerRecord containing test data
|
||||
ConsumerRecord<Long, CollectRep.MetricsData> record =
|
||||
new ConsumerRecord<>("metricsDataTopic", 0, 0L, 1L, expectedData);
|
||||
|
||||
// Create a ConsumerRecords containing a single record.
|
||||
Map<TopicPartition, List<ConsumerRecord<Long, CollectRep.MetricsData>>> recordsMap =
|
||||
Collections.singletonMap(
|
||||
new TopicPartition("metricsDataTopic", 0),
|
||||
Collections.singletonList(record));
|
||||
ConsumerRecords<Long, CollectRep.MetricsData> records = new ConsumerRecords<>(recordsMap);
|
||||
|
||||
when(metricsDataToAlertConsumer.poll(any(Duration.class))).thenReturn(records);
|
||||
|
||||
CollectRep.MetricsData result = kafkaCommonDataQueue.pollMetricsDataToAlerter();
|
||||
assertEquals(expectedData, result);
|
||||
|
||||
verify(metricsDataToAlertConsumer).commitAsync();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSendLogEntry() {
|
||||
// Create a test log entry with comprehensive data
|
||||
Map<String, Object> attributes = new HashMap<>();
|
||||
attributes.put("service.name", "hertzbeat");
|
||||
attributes.put("service.version", "1.0.0");
|
||||
|
||||
LogEntry logEntry = LogEntry.builder()
|
||||
.timeUnixNano(Instant.now().toEpochMilli() * 1_000_000L)
|
||||
.severityNumber(9) // INFO level
|
||||
.severityText("INFO")
|
||||
.body("Test log message for Kafka queue")
|
||||
.attributes(attributes)
|
||||
.traceId("1234567890abcdef1234567890abcdef")
|
||||
.spanId("1234567890abcdef")
|
||||
.build();
|
||||
|
||||
// Test sending log entry
|
||||
kafkaCommonDataQueue.sendLogEntry(logEntry);
|
||||
|
||||
// Verify that the producer was called
|
||||
verify(logEntryProducer).send(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSendLogEntryToStorage() {
|
||||
// Create a test log entry for storage
|
||||
LogEntry logEntry = LogEntry.builder()
|
||||
.timeUnixNano(Instant.now().toEpochMilli() * 1_000_000L)
|
||||
.severityNumber(17) // ERROR level
|
||||
.severityText("ERROR")
|
||||
.body("Error log message for storage via Kafka")
|
||||
.build();
|
||||
|
||||
// Test sending log entry to storage
|
||||
kafkaCommonDataQueue.sendLogEntryToStorage(logEntry);
|
||||
|
||||
// Verify that the producer was called
|
||||
verify(logEntryProducer).send(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPollLogEntry() throws InterruptedException {
|
||||
// Create test log entry
|
||||
LogEntry expectedLogEntry = LogEntry.builder()
|
||||
.timeUnixNano(Instant.now().toEpochMilli() * 1_000_000L)
|
||||
.severityNumber(13) // WARN level
|
||||
.severityText("WARN")
|
||||
.body("Test warning log message")
|
||||
.build();
|
||||
|
||||
// Create a ConsumerRecord containing test log entry
|
||||
ConsumerRecord<Long, LogEntry> record =
|
||||
new ConsumerRecord<>("logEntryDataTopic", 0, 0L, 1L, expectedLogEntry);
|
||||
|
||||
// Create ConsumerRecords containing the log entry record
|
||||
Map<TopicPartition, List<ConsumerRecord<Long, LogEntry>>> recordsMap =
|
||||
Collections.singletonMap(
|
||||
new TopicPartition("logEntryDataTopic", 0),
|
||||
Collections.singletonList(record));
|
||||
ConsumerRecords<Long, LogEntry> records = new ConsumerRecords<>(recordsMap);
|
||||
|
||||
when(logEntryConsumer.poll(any(Duration.class))).thenReturn(records);
|
||||
|
||||
LogEntry result = kafkaCommonDataQueue.pollLogEntry();
|
||||
|
||||
assertEquals(expectedLogEntry, result);
|
||||
verify(logEntryConsumer).commitAsync();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPollLogEntryToStorage() throws InterruptedException {
|
||||
// Create test log entry for storage
|
||||
LogEntry expectedLogEntry = LogEntry.builder()
|
||||
.timeUnixNano(Instant.now().toEpochMilli() * 1_000_000L)
|
||||
.severityNumber(21) // FATAL level
|
||||
.severityText("FATAL")
|
||||
.body("Critical error log for storage")
|
||||
.build();
|
||||
|
||||
// Create a ConsumerRecord containing test log entry
|
||||
ConsumerRecord<Long, LogEntry> record =
|
||||
new ConsumerRecord<>("logEntryDataToStorageTopic", 0, 0L, 1L, expectedLogEntry);
|
||||
|
||||
// Create ConsumerRecords containing the log entry record
|
||||
Map<TopicPartition, List<ConsumerRecord<Long, LogEntry>>> recordsMap =
|
||||
Collections.singletonMap(
|
||||
new TopicPartition("logEntryDataToStorageTopic", 0),
|
||||
Collections.singletonList(record));
|
||||
ConsumerRecords<Long, LogEntry> records = new ConsumerRecords<>(recordsMap);
|
||||
|
||||
when(logEntryToStorageConsumer.poll(any(Duration.class))).thenReturn(records);
|
||||
|
||||
LogEntry result = kafkaCommonDataQueue.pollLogEntryToStorage();
|
||||
|
||||
assertEquals(expectedLogEntry, result);
|
||||
verify(logEntryToStorageConsumer).commitAsync();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDestroy() throws Exception {
|
||||
kafkaCommonDataQueue.destroy();
|
||||
|
||||
// Verify that all producers and consumers are closed
|
||||
verify(metricsDataToAlertConsumer).close();
|
||||
verify(metricsDataProducer).close();
|
||||
verify(logEntryProducer).close();
|
||||
verify(logEntryConsumer).close();
|
||||
verify(logEntryToStorageConsumer).close();
|
||||
}
|
||||
|
||||
private void setPrivateField(Object object, String fieldName, Object value) throws Exception {
|
||||
Field field = object.getClass().getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
field.set(object, value);
|
||||
}
|
||||
}
|
||||
+204
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* 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.queue.impl;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import io.lettuce.core.RedisClient;
|
||||
import io.lettuce.core.RedisURI;
|
||||
import io.lettuce.core.api.StatefulRedisConnection;
|
||||
import io.lettuce.core.api.sync.RedisCommands;
|
||||
import io.lettuce.core.KeyValue;
|
||||
import java.time.Instant;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.hertzbeat.common.config.CommonProperties;
|
||||
import org.apache.hertzbeat.common.entity.log.LogEntry;
|
||||
import org.apache.hertzbeat.common.entity.message.CollectRep;
|
||||
import org.apache.hertzbeat.common.serialize.RedisLogEntryCodec;
|
||||
import org.apache.hertzbeat.common.serialize.RedisMetricsDataCodec;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
/**
|
||||
* test for {@link RedisCommonDataQueue}
|
||||
*/
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class RedisCommonDataQueueTest {
|
||||
|
||||
@Mock
|
||||
private StatefulRedisConnection<String, CollectRep.MetricsData> connection;
|
||||
@Mock
|
||||
private StatefulRedisConnection<String, LogEntry> logEntryConnection;
|
||||
|
||||
@Mock
|
||||
private RedisCommands<String, CollectRep.MetricsData> syncCommands;
|
||||
@Mock
|
||||
private RedisCommands<String, LogEntry> logEntrySyncCommands;
|
||||
|
||||
private RedisClient redisClient;
|
||||
private CommonProperties commonProperties;
|
||||
private CommonProperties.RedisProperties redisProperties;
|
||||
private RedisCommonDataQueue redisCommonDataQueue;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
redisClient = mock(RedisClient.class);
|
||||
commonProperties = mock(CommonProperties.class);
|
||||
redisProperties = mock(CommonProperties.RedisProperties.class);
|
||||
CommonProperties.DataQueueProperties dataQueueProperties = mock(CommonProperties.DataQueueProperties.class);
|
||||
|
||||
when(commonProperties.getQueue()).thenReturn(dataQueueProperties);
|
||||
when(dataQueueProperties.getRedis()).thenReturn(redisProperties);
|
||||
when(redisProperties.getMetricsDataQueueNameToAlerter()).thenReturn("metricsDataQueueToAlerter");
|
||||
when(redisProperties.getLogEntryQueueName()).thenReturn("logEntryQueue");
|
||||
when(redisProperties.getLogEntryToStorageQueueName()).thenReturn("logEntryToStorageQueue");
|
||||
when(redisProperties.getRedisHost()).thenReturn("localhost");
|
||||
when(redisProperties.getRedisPort()).thenReturn(6379);
|
||||
when(redisProperties.getWaitTimeout()).thenReturn(1L);
|
||||
try (MockedStatic<RedisClient> mockedRedisClient = mockStatic(RedisClient.class)) {
|
||||
mockedRedisClient.when(() -> RedisClient.create(any(RedisURI.class))).thenReturn(redisClient);
|
||||
when(redisClient.connect(any(RedisMetricsDataCodec.class))).thenReturn(connection);
|
||||
when(redisClient.connect(any(RedisLogEntryCodec.class))).thenReturn(logEntryConnection);
|
||||
when(logEntryConnection.sync()).thenReturn(logEntrySyncCommands);
|
||||
when(connection.sync()).thenReturn(syncCommands);
|
||||
|
||||
redisCommonDataQueue = new RedisCommonDataQueue(commonProperties);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPollMetricsDataToAlerter() throws Exception {
|
||||
CollectRep.MetricsData metricsData = CollectRep.MetricsData.newBuilder()
|
||||
.setMetrics("test metrics")
|
||||
.build();
|
||||
String queueName = "metricsDataQueueToAlerter";
|
||||
|
||||
when(syncCommands.brpop(1L, queueName)).thenReturn(KeyValue.just(queueName, metricsData));
|
||||
|
||||
CollectRep.MetricsData actualMetricsData = redisCommonDataQueue.pollMetricsDataToAlerter();
|
||||
assertEquals(metricsData, actualMetricsData);
|
||||
verify(syncCommands).brpop(1L, queueName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendMetricsData() throws Exception {
|
||||
CollectRep.MetricsData metricsData = CollectRep.MetricsData.newBuilder()
|
||||
.setMetrics("test metrics")
|
||||
.build();
|
||||
|
||||
redisCommonDataQueue.sendMetricsData(metricsData);
|
||||
|
||||
verify(syncCommands).lpush("metricsDataQueueToAlerter", metricsData);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendLogEntry() {
|
||||
// Create a test log entry with comprehensive data
|
||||
Map<String, Object> attributes = new HashMap<>();
|
||||
attributes.put("service.name", "hertzbeat");
|
||||
attributes.put("service.version", "1.0.0");
|
||||
|
||||
LogEntry logEntry = LogEntry.builder()
|
||||
.timeUnixNano(Instant.now().toEpochMilli() * 1_000_000L)
|
||||
.severityNumber(9) // INFO level
|
||||
.severityText("INFO")
|
||||
.body("Test log message for Redis queue")
|
||||
.attributes(attributes)
|
||||
.traceId("1234567890abcdef1234567890abcdef")
|
||||
.spanId("1234567890abcdef")
|
||||
.build();
|
||||
|
||||
// Test sending log entry
|
||||
redisCommonDataQueue.sendLogEntry(logEntry);
|
||||
|
||||
// Verify that the Redis commands were called
|
||||
verify(logEntrySyncCommands).lpush("logEntryQueue", logEntry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendLogEntryToStorage() {
|
||||
// Create a test log entry for storage
|
||||
LogEntry logEntry = LogEntry.builder()
|
||||
.timeUnixNano(Instant.now().toEpochMilli() * 1_000_000L)
|
||||
.severityNumber(17) // ERROR level
|
||||
.severityText("ERROR")
|
||||
.body("Error log message for storage via Redis")
|
||||
.build();
|
||||
|
||||
// Test sending log entry to storage
|
||||
redisCommonDataQueue.sendLogEntryToStorage(logEntry);
|
||||
|
||||
// Verify that the Redis commands were called
|
||||
verify(logEntrySyncCommands).lpush("logEntryToStorageQueue", logEntry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPollLogEntry() throws Exception {
|
||||
// Create test log entry
|
||||
LogEntry expectedLogEntry = LogEntry.builder()
|
||||
.timeUnixNano(Instant.now().toEpochMilli() * 1_000_000L)
|
||||
.severityNumber(13) // WARN level
|
||||
.severityText("WARN")
|
||||
.body("Test warning log message")
|
||||
.build();
|
||||
String queueName = "logEntryQueue";
|
||||
|
||||
when(logEntrySyncCommands.brpop(1L, queueName)).thenReturn(KeyValue.just(queueName, expectedLogEntry));
|
||||
|
||||
LogEntry result = redisCommonDataQueue.pollLogEntry();
|
||||
|
||||
assertEquals(expectedLogEntry, result);
|
||||
verify(logEntrySyncCommands).brpop(1L, "logEntryQueue");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPollLogEntryToStorage() throws Exception {
|
||||
// Create test log entry for storage
|
||||
LogEntry expectedLogEntry = LogEntry.builder()
|
||||
.timeUnixNano(Instant.now().toEpochMilli() * 1_000_000L)
|
||||
.severityNumber(21) // FATAL level
|
||||
.severityText("FATAL")
|
||||
.body("Critical error log for storage")
|
||||
.build();
|
||||
String queueName = "logEntryToStorageQueue";
|
||||
|
||||
when(logEntrySyncCommands.brpop(1L, queueName)).thenReturn(KeyValue.just(queueName, expectedLogEntry));
|
||||
LogEntry result = redisCommonDataQueue.pollLogEntryToStorage();
|
||||
|
||||
assertEquals(expectedLogEntry, result);
|
||||
verify(logEntrySyncCommands).brpop(1L, "logEntryToStorageQueue");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDestroy() {
|
||||
redisCommonDataQueue.destroy();
|
||||
verify(connection).close();
|
||||
verify(logEntryConnection).close();
|
||||
verify(redisClient).shutdown();
|
||||
}
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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.support;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import org.apache.hertzbeat.common.concurrent.AdmissionMode;
|
||||
import org.apache.hertzbeat.common.config.VirtualThreadProperties;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Test for {@link CommonThreadPool}.
|
||||
*/
|
||||
class CommonThreadPoolTest {
|
||||
|
||||
private CommonThreadPool commonThreadPool;
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws Exception {
|
||||
if (commonThreadPool != null) {
|
||||
commonThreadPool.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExecuteRunsOnVirtualThread() throws Exception {
|
||||
commonThreadPool = new CommonThreadPool();
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
AtomicBoolean virtualThread = new AtomicBoolean(false);
|
||||
|
||||
commonThreadPool.execute(() -> {
|
||||
virtualThread.set(Thread.currentThread().isVirtual());
|
||||
latch.countDown();
|
||||
});
|
||||
|
||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
assertTrue(virtualThread.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExecuteLongRunningRunsOnPlatformThread() throws Exception {
|
||||
commonThreadPool = new CommonThreadPool();
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
AtomicBoolean virtualThread = new AtomicBoolean(true);
|
||||
|
||||
commonThreadPool.executeLongRunning(() -> {
|
||||
virtualThread.set(Thread.currentThread().isVirtual());
|
||||
latch.countDown();
|
||||
});
|
||||
|
||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
assertFalse(virtualThread.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExecuteRejectsWhenConcurrencyLimitReached() throws Exception {
|
||||
VirtualThreadProperties properties = new VirtualThreadProperties(
|
||||
true,
|
||||
VirtualThreadProperties.PoolProperties.collectorDefaults(),
|
||||
new VirtualThreadProperties.PoolProperties(AdmissionMode.LIMIT_AND_REJECT, 1),
|
||||
VirtualThreadProperties.PoolProperties.managerDefaults(),
|
||||
VirtualThreadProperties.AlerterProperties.defaults(),
|
||||
VirtualThreadProperties.PoolProperties.warehouseDefaults(),
|
||||
VirtualThreadProperties.AsyncProperties.defaults());
|
||||
commonThreadPool = new CommonThreadPool(properties);
|
||||
|
||||
CountDownLatch started = new CountDownLatch(1);
|
||||
CountDownLatch release = new CountDownLatch(1);
|
||||
commonThreadPool.execute(() -> {
|
||||
started.countDown();
|
||||
try {
|
||||
release.await(5, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
});
|
||||
assertTrue(started.await(5, TimeUnit.SECONDS));
|
||||
|
||||
try {
|
||||
assertThrows(RejectedExecutionException.class, () -> commonThreadPool.execute(() -> {
|
||||
}));
|
||||
} finally {
|
||||
release.countDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.support;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import java.util.ResourceBundle;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Test case for {@link ResourceBundleUtf8Control}
|
||||
*/
|
||||
class ResourceBundleUtf8ControlTest {
|
||||
|
||||
@Test
|
||||
void testNewBundleWithPropertiesFormat() throws IllegalAccessException, InstantiationException, IOException {
|
||||
|
||||
ResourceBundle.Control control = new ResourceBundleUtf8Control();
|
||||
ClassLoader loader = getClass().getClassLoader();
|
||||
String baseName = "msg";
|
||||
|
||||
ResourceBundle bundle = control.newBundle(baseName, Locale.ENGLISH, "java.properties", loader, false);
|
||||
assertNotNull(bundle);
|
||||
assertEquals("Hello, World!", bundle.getString("hello"));
|
||||
|
||||
bundle = control.newBundle(baseName, Locale.ROOT, "java.properties", loader, false);
|
||||
assertNotNull(bundle);
|
||||
assertEquals("你好", bundle.getString("hello"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNewBundleWithClassFormat() throws IllegalAccessException, InstantiationException, IOException {
|
||||
|
||||
ResourceBundle.Control control = new ResourceBundleUtf8Control();
|
||||
ClassLoader loader = getClass().getClassLoader();
|
||||
String baseName = "dummyClassBundle";
|
||||
|
||||
ResourceBundle bundle = control.newBundle(baseName, Locale.ENGLISH, "java.class", loader, false);
|
||||
//because not have an actual class, bundle should be null
|
||||
assertNull(bundle);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testReloading() throws IllegalAccessException, InstantiationException, IOException {
|
||||
ResourceBundle.Control control = new ResourceBundleUtf8Control();
|
||||
ClassLoader loader = getClass().getClassLoader();
|
||||
String baseName = "msg";
|
||||
|
||||
// Test with reload flag
|
||||
ResourceBundle bundle = control.newBundle(baseName, Locale.ENGLISH, "java.properties", loader, true);
|
||||
assertNotNull(bundle);
|
||||
assertEquals("Hello, World!", bundle.getString("hello"));
|
||||
}
|
||||
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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.support;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
/**
|
||||
* Test case for {@link SpringContextHolder}
|
||||
*/
|
||||
class SpringContextHolderTest {
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private ConfigurableApplicationContext configurableApplicationContext;
|
||||
|
||||
private SpringContextHolder springContextHolder;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
|
||||
applicationContext = mock(ApplicationContext.class);
|
||||
configurableApplicationContext = mock(ConfigurableApplicationContext.class);
|
||||
springContextHolder = new SpringContextHolder();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetApplicationContext() throws BeansException {
|
||||
|
||||
springContextHolder.setApplicationContext(configurableApplicationContext);
|
||||
|
||||
assertNotNull(SpringContextHolder.getApplicationContext());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetApplicationContext() {
|
||||
|
||||
springContextHolder.setApplicationContext(applicationContext);
|
||||
assertNotNull(SpringContextHolder.getApplicationContext());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBeanByClass() {
|
||||
|
||||
Class<String> beanClass = String.class;
|
||||
String bean = "bean";
|
||||
when(applicationContext.getBean(beanClass)).thenReturn(bean);
|
||||
|
||||
springContextHolder.setApplicationContext(applicationContext);
|
||||
String retrievedBean = SpringContextHolder.getBean(beanClass);
|
||||
|
||||
assertEquals(bean, retrievedBean);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShutdown() {
|
||||
|
||||
springContextHolder.setApplicationContext(configurableApplicationContext);
|
||||
SpringContextHolder.shutdown();
|
||||
|
||||
verify(configurableApplicationContext, times(1)).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsActive() {
|
||||
|
||||
when(configurableApplicationContext.isActive()).thenReturn(true);
|
||||
springContextHolder.setApplicationContext(configurableApplicationContext);
|
||||
assertTrue(SpringContextHolder.isActive());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAssertApplicationContextThrowsException() {
|
||||
|
||||
RuntimeException exception = assertThrows(RuntimeException.class, SpringContextHolder::getApplicationContext);
|
||||
assertEquals(
|
||||
"applicationContext is null, please inject the springContextHolder",
|
||||
exception.getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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.support.vaild;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
import jakarta.validation.ConstraintValidatorContext;
|
||||
import org.apache.hertzbeat.common.support.valid.EmailParamValidator;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
/**
|
||||
* Test case for {@link EmailParamValidator}
|
||||
*/
|
||||
|
||||
class EmailParamValidatorTest {
|
||||
|
||||
@InjectMocks
|
||||
private EmailParamValidator emailParamValidator;
|
||||
|
||||
@Mock
|
||||
private ConstraintValidatorContext context;
|
||||
|
||||
@Mock
|
||||
private ConstraintValidatorContext.ConstraintViolationBuilder constraintViolationBuilder;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(context.buildConstraintViolationWithTemplate(any())).thenReturn(constraintViolationBuilder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsValid() {
|
||||
boolean result = emailParamValidator.isValid(null, context);
|
||||
assertFalse(result);
|
||||
|
||||
result = emailParamValidator.isValid("123456345@qq.com", context);
|
||||
assertTrue(result);
|
||||
|
||||
result = emailParamValidator.isValid("", context);
|
||||
assertFalse(result);
|
||||
|
||||
result = emailParamValidator.isValid(" ", context);
|
||||
assertFalse(result);
|
||||
|
||||
result = emailParamValidator.isValid("test@example.com", context);
|
||||
assertTrue(result);
|
||||
|
||||
result = emailParamValidator.isValid("test@example", context);
|
||||
assertFalse(result);
|
||||
|
||||
result = emailParamValidator.isValid("test@sub.example.com", context);
|
||||
assertTrue(result);
|
||||
|
||||
|
||||
String longEmail = "verylongemailaddress@subdomain.domain.example.com";
|
||||
result = emailParamValidator.isValid(longEmail, context);
|
||||
assertTrue(result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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.support.vaild;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
import jakarta.validation.ConstraintValidatorContext;
|
||||
import org.apache.hertzbeat.common.support.valid.HostParamValidator;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
/**
|
||||
* Test case for {@link HostParamValidator}
|
||||
*/
|
||||
|
||||
class HostParamValidatorTest {
|
||||
|
||||
@InjectMocks
|
||||
private HostParamValidator hostParamValidator;
|
||||
|
||||
@Mock
|
||||
private ConstraintValidatorContext context;
|
||||
|
||||
@Mock
|
||||
private ConstraintValidatorContext.ConstraintViolationBuilder constraintViolationBuilder;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(context.buildConstraintViolationWithTemplate(any())).thenReturn(constraintViolationBuilder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsValid() {
|
||||
boolean result = hostParamValidator.isValid(null, context);
|
||||
assertTrue(result);
|
||||
|
||||
result = hostParamValidator.isValid("", context);
|
||||
assertTrue(result);
|
||||
|
||||
result = hostParamValidator.isValid(" ", context);
|
||||
assertTrue(result);
|
||||
|
||||
result = hostParamValidator.isValid("192.168.1.1", context);
|
||||
assertTrue(result);
|
||||
|
||||
result = hostParamValidator.isValid("2001:0db8:85a3:0000:0000:8a2e:0370:7334", context);
|
||||
assertTrue(result);
|
||||
|
||||
result = hostParamValidator.isValid("www.example.com", context);
|
||||
assertTrue(result);
|
||||
|
||||
result = hostParamValidator.isValid("http://www.example.com", context);
|
||||
assertTrue(result);
|
||||
|
||||
result = hostParamValidator.isValid("https://www.baidu.com", context);
|
||||
assertTrue(result);
|
||||
|
||||
result = hostParamValidator.isValid("ht!tp://www.example.com", context);
|
||||
assertFalse(result);
|
||||
}
|
||||
}
|
||||
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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.support.vaild;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
import jakarta.validation.ConstraintValidatorContext;
|
||||
import org.apache.hertzbeat.common.support.valid.PhoneNumParamValidator;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
/**
|
||||
* Test case for {@link PhoneNumParamValidator}
|
||||
*/
|
||||
|
||||
class PhoneNumParamValidatorTest {
|
||||
|
||||
@InjectMocks
|
||||
private PhoneNumParamValidator phoneNumParamValidator;
|
||||
|
||||
@Mock
|
||||
private ConstraintValidatorContext context;
|
||||
|
||||
@Mock
|
||||
private ConstraintValidatorContext.ConstraintViolationBuilder constraintViolationBuilder;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(context.buildConstraintViolationWithTemplate(any())).thenReturn(constraintViolationBuilder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsValid() {
|
||||
boolean result = phoneNumParamValidator.isValid(null, context);
|
||||
assertFalse(result);
|
||||
|
||||
result = phoneNumParamValidator.isValid("", context);
|
||||
assertFalse(result);
|
||||
|
||||
result = phoneNumParamValidator.isValid("123456", context);
|
||||
assertFalse(result);
|
||||
|
||||
result = phoneNumParamValidator.isValid("abc123", context);
|
||||
assertFalse(result);
|
||||
|
||||
result = phoneNumParamValidator.isValid("13900001234", context);
|
||||
assertTrue(result);
|
||||
|
||||
result = phoneNumParamValidator.isValid("1234567890123456789", context);
|
||||
assertFalse(result);
|
||||
}
|
||||
}
|
||||
|
||||
+267
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* 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.support.valid;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
/**
|
||||
* Test for {@link SqlSecurityValidator}
|
||||
*/
|
||||
class SqlSecurityValidatorTest {
|
||||
|
||||
private SqlSecurityValidator validator;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
validator = new SqlSecurityValidator(Arrays.asList("hertzbeat_logs", "app_logs", "access_logs"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidSelectStatement() {
|
||||
assertDoesNotThrow(() -> validator.validate("SELECT * FROM hertzbeat_logs"));
|
||||
assertDoesNotThrow(() -> validator.validate("SELECT id, message FROM hertzbeat_logs WHERE level = 'ERROR'"));
|
||||
assertDoesNotThrow(() -> validator.validate("SELECT COUNT(*) FROM app_logs"));
|
||||
assertDoesNotThrow(() -> validator.validate("select * from HERTZBEAT_LOGS")); // case insensitive
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSelectWithJoin() {
|
||||
assertDoesNotThrow(() -> validator.validate(
|
||||
"SELECT a.id, b.message FROM hertzbeat_logs a JOIN app_logs b ON a.id = b.id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSelectWithSubqueryNotAllowed() {
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> validator.validate("SELECT * FROM hertzbeat_logs WHERE id IN (SELECT id FROM app_logs)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSelectWithSubqueryInFromNotAllowed() {
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> validator.validate("SELECT * FROM (SELECT * FROM hertzbeat_logs) AS subq"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEmptySql() {
|
||||
assertThrows(SqlSecurityException.class, () -> validator.validate(null));
|
||||
assertThrows(SqlSecurityException.class, () -> validator.validate(""));
|
||||
assertThrows(SqlSecurityException.class, () -> validator.validate(" "));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInvalidSqlSyntax() {
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> validator.validate("SELECT * FORM hertzbeat_logs")); // typo: FORM instead of FROM
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInsertNotAllowed() {
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> validator.validate("INSERT INTO hertzbeat_logs (message) VALUES ('test')"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpdateNotAllowed() {
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> validator.validate("UPDATE hertzbeat_logs SET message = 'test' WHERE id = 1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeleteNotAllowed() {
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> validator.validate("DELETE FROM hertzbeat_logs WHERE id = 1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDropNotAllowed() {
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> validator.validate("DROP TABLE hertzbeat_logs"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTruncateNotAllowed() {
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> validator.validate("TRUNCATE TABLE hertzbeat_logs"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAlterNotAllowed() {
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> validator.validate("ALTER TABLE hertzbeat_logs ADD COLUMN new_col VARCHAR(100)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreateNotAllowed() {
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> validator.validate("CREATE TABLE new_table (id INT)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUnauthorizedTable() {
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> validator.validate("SELECT * FROM users"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUnauthorizedTableInJoin() {
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> validator.validate("SELECT * FROM hertzbeat_logs JOIN users ON hertzbeat_logs.user_id = users.id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUnauthorizedTableInSubquery() {
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> validator.validate("SELECT * FROM hertzbeat_logs WHERE user_id IN (SELECT id FROM users)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTableWithQuotes() {
|
||||
assertDoesNotThrow(() -> validator.validate("SELECT * FROM \"hertzbeat_logs\""));
|
||||
assertDoesNotThrow(() -> validator.validate("SELECT * FROM `hertzbeat_logs`"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEmptyAllowedTables() {
|
||||
SqlSecurityValidator emptyValidator = new SqlSecurityValidator(Collections.emptyList());
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> emptyValidator.validate("SELECT * FROM any_table"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNullAllowedTables() {
|
||||
SqlSecurityValidator nullValidator = new SqlSecurityValidator(null);
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> nullValidator.validate("SELECT * FROM any_table"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testComplexSelectWithAggregation() {
|
||||
assertDoesNotThrow(() -> validator.validate(
|
||||
"SELECT level, COUNT(*) as cnt FROM hertzbeat_logs GROUP BY level HAVING COUNT(*) > 10 ORDER BY cnt DESC LIMIT 100"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSelectWithUnionNotAllowed() {
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> validator.validate("SELECT * FROM hertzbeat_logs UNION SELECT * FROM app_logs"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSelectWithUnionAllNotAllowed() {
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> validator.validate("SELECT * FROM hertzbeat_logs UNION ALL SELECT * FROM app_logs"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSelectWithIntersectNotAllowed() {
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> validator.validate("SELECT * FROM hertzbeat_logs INTERSECT SELECT * FROM app_logs"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSelectWithExceptNotAllowed() {
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> validator.validate("SELECT * FROM hertzbeat_logs EXCEPT SELECT * FROM app_logs"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLateralSubqueryNotAllowed() {
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> validator.validate("SELECT * FROM hertzbeat_logs, LATERAL (SELECT * FROM app_logs) AS t"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testWithClauseNotAllowed() {
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> validator.validate("WITH cte AS (SELECT * FROM hertzbeat_logs) SELECT * FROM cte"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSqlInjectionAttemptDropTable() {
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> validator.validate("DROP TABLE users"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSqlInjectionAttemptUnauthorizedTable() {
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> validator.validate("SELECT * FROM users"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSqlInjectionAttemptDeleteFrom() {
|
||||
assertThrows(SqlSecurityException.class,
|
||||
() -> validator.validate("DELETE FROM hertzbeat_logs WHERE 1=1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBypassInSelectItems() {
|
||||
assertThrows(SqlSecurityException.class, () -> validator.validate(
|
||||
"SELECT (SELECT password FROM secret_table) FROM hertzbeat_logs"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBypassInWhereClauseAnd() {
|
||||
assertThrows(SqlSecurityException.class, () -> validator.validate(
|
||||
"SELECT * FROM hertzbeat_logs WHERE 1=1 AND id IN (SELECT id FROM secret_table)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBypassInFunction() {
|
||||
assertThrows(SqlSecurityException.class, () -> validator.validate(
|
||||
"SELECT * FROM hertzbeat_logs WHERE id = abs((SELECT count(*) FROM secret_table))"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBypassInCaseWhen() {
|
||||
assertThrows(SqlSecurityException.class, () -> validator.validate(
|
||||
"SELECT * FROM hertzbeat_logs WHERE status = (CASE WHEN (SELECT 1 FROM secret_table)=1 THEN 1 ELSE 0 END)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBypassWithAndExpression() {
|
||||
assertThrows(SqlSecurityException.class, () -> validator.validate(
|
||||
"SELECT * FROM hertzbeat_logs WHERE 1=1 AND id = (SELECT id FROM secret_table)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBypassWithGreaterThan() {
|
||||
assertThrows(SqlSecurityException.class, () -> validator.validate(
|
||||
"SELECT * FROM hertzbeat_logs WHERE id > (SELECT count(*) FROM secret_table)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBypassWithBetween() {
|
||||
assertThrows(SqlSecurityException.class, () -> validator.validate(
|
||||
"SELECT * FROM hertzbeat_logs WHERE id BETWEEN 1 AND (SELECT id FROM secret_table)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBypassWithMathOperations() {
|
||||
assertThrows(SqlSecurityException.class, () -> validator.validate(
|
||||
"SELECT * FROM hertzbeat_logs WHERE id = 1 + (SELECT id FROM secret_table)"));
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import org.apache.hertzbeat.common.constants.ExportFileConstants;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* test case for {@link FileUtil}.
|
||||
*/
|
||||
|
||||
class FileUtilTest {
|
||||
|
||||
private static final String EXCEL_TYPE = "application/vnd.ms-excel";
|
||||
private static final String YAML_TYPE = "application/x-yaml";
|
||||
|
||||
private MockMultipartFile jsonFile;
|
||||
private MockMultipartFile excelFile;
|
||||
private MockMultipartFile yamlFile;
|
||||
private MockMultipartFile emptyFile;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
|
||||
jsonFile = new MockMultipartFile("file", "test.json", MediaType.APPLICATION_JSON_VALUE,
|
||||
"test content".getBytes(StandardCharsets.UTF_8));
|
||||
excelFile = new MockMultipartFile("file", "test.xlsx", EXCEL_TYPE,
|
||||
"test content".getBytes(StandardCharsets.UTF_8));
|
||||
yamlFile = new MockMultipartFile("file", "test.yaml", YAML_TYPE,
|
||||
"test content".getBytes(StandardCharsets.UTF_8));
|
||||
emptyFile = new MockMultipartFile("file", "", null, (byte[]) null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetFileName() {
|
||||
|
||||
assertEquals("test.json", FileUtil.getFileName(jsonFile));
|
||||
assertEquals("test.xlsx", FileUtil.getFileName(excelFile));
|
||||
assertEquals("test.yaml", FileUtil.getFileName(yamlFile));
|
||||
assertEquals("", FileUtil.getFileName(emptyFile));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetFileType() {
|
||||
|
||||
assertEquals(ExportFileConstants.JsonFile.TYPE, FileUtil.getFileType(jsonFile));
|
||||
assertEquals(ExportFileConstants.ExcelFile.TYPE, FileUtil.getFileType(excelFile));
|
||||
assertEquals(ExportFileConstants.YamlFile.TYPE, FileUtil.getFileType(yamlFile));
|
||||
assertEquals("", FileUtil.getFileType(emptyFile));
|
||||
}
|
||||
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import java.util.Locale;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
/**
|
||||
* Test case for {@link ResourceBundleUtil}
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class ResourceBundleUtilTest {
|
||||
|
||||
private static final String BUNDLE_NAME = "TestBundle";
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
Locale.setDefault(Locale.US);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetBundleWithValidBundleName() {
|
||||
try (MockedStatic<ResourceBundle> mockedResourceBundle = mockStatic(ResourceBundle.class)) {
|
||||
ResourceBundle mockBundle = Mockito.mock(ResourceBundle.class);
|
||||
|
||||
mockedResourceBundle.when(
|
||||
() -> ResourceBundle.getBundle(
|
||||
Mockito.eq(BUNDLE_NAME),
|
||||
Mockito.any(ResourceBundle.Control.class)
|
||||
)
|
||||
).thenReturn(mockBundle);
|
||||
|
||||
ResourceBundle bundle = ResourceBundleUtil.getBundle(BUNDLE_NAME);
|
||||
|
||||
assertNotNull(bundle);
|
||||
assertEquals(mockBundle, bundle);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetBundleByInvalidBundleName() {
|
||||
try (MockedStatic<ResourceBundle> mockedResourceBundle = mockStatic(ResourceBundle.class)) {
|
||||
mockedResourceBundle.when(
|
||||
() -> ResourceBundle.getBundle(
|
||||
Mockito.eq(BUNDLE_NAME),
|
||||
Mockito.any(ResourceBundle.Control.class)
|
||||
)
|
||||
).thenThrow(new MissingResourceException("Missing bundle", "ResourceBundle", BUNDLE_NAME));
|
||||
|
||||
ResourceBundle mockDefaultBundle = Mockito.mock(ResourceBundle.class);
|
||||
|
||||
mockedResourceBundle.when(() -> ResourceBundle.getBundle(
|
||||
Mockito.eq(BUNDLE_NAME),
|
||||
Mockito.eq(Locale.US),
|
||||
Mockito.any(ResourceBundle.Control.class))
|
||||
).thenReturn(mockDefaultBundle);
|
||||
|
||||
ResourceBundle bundle = ResourceBundleUtil.getBundle(BUNDLE_NAME);
|
||||
|
||||
assertNotNull(bundle);
|
||||
assertEquals(mockDefaultBundle, bundle);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import javax.naming.AuthenticationException;
|
||||
|
||||
import org.apache.hertzbeat.common.constants.CommonConstants;
|
||||
import org.apache.hertzbeat.common.entity.dto.Message;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
/**
|
||||
* Test for {@link ResponseUtil}
|
||||
*/
|
||||
public class ResponseUtilTest {
|
||||
@Test
|
||||
public void testHandle() {
|
||||
assertDoesNotThrow(() -> {
|
||||
ResponseUtil.handle(() -> "test");
|
||||
});
|
||||
|
||||
assertDoesNotThrow(() -> {
|
||||
ResponseEntity<Message<String>> resp = ResponseUtil.handle(() -> {
|
||||
throw new RuntimeException("test");
|
||||
});
|
||||
assertEquals(CommonConstants.FAIL_CODE, resp.getBody().getCode());
|
||||
});
|
||||
|
||||
assertDoesNotThrow(() -> {
|
||||
ResponseEntity<Message<String>> resp = ResponseUtil.handle(() -> {
|
||||
throw new AuthenticationException("test");
|
||||
});
|
||||
assertEquals(CommonConstants.LOGIN_FAILED_CODE, resp.getBody().getCode());
|
||||
});
|
||||
|
||||
assertDoesNotThrow(() -> {
|
||||
ResponseUtil.Runnable run = new ResponseUtil.Runnable() {
|
||||
public void run() {
|
||||
throw new UnsupportedOperationException("Unimplemented method 'run'");
|
||||
}
|
||||
};
|
||||
ResponseEntity<Message<String>> resp = ResponseUtil.handle(run);
|
||||
assertEquals(CommonConstants.FAIL_CODE, resp.getBody().getCode());
|
||||
});
|
||||
|
||||
assertDoesNotThrow(() -> {
|
||||
ResponseUtil.Runnable run = new ResponseUtil.Runnable() {
|
||||
public void run() throws AuthenticationException {
|
||||
throw new AuthenticationException("test");
|
||||
}
|
||||
};
|
||||
ResponseEntity<Message<String>> resp = ResponseUtil.handle(run);
|
||||
assertEquals(CommonConstants.LOGIN_FAILED_CODE, resp.getBody().getCode());
|
||||
});
|
||||
|
||||
assertDoesNotThrow(() -> {
|
||||
ResponseEntity<Message<String>> resp = ResponseUtil.handle(() -> {});
|
||||
assertEquals(CommonConstants.SUCCESS_CODE, resp.getBody().getCode());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* InnerResponseUtilTest
|
||||
*/
|
||||
public interface InnerResponseUtilTest {
|
||||
void run() throws Exception;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
# 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.
|
||||
|
||||
hello=你好
|
||||
@@ -0,0 +1,16 @@
|
||||
# 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.
|
||||
|
||||
hello=Hello, World!
|
||||
Reference in New Issue
Block a user