parent
							
								
									143859e3eb
								
							
						
					
					
						commit
						045f41cafe
					
				@ -1,15 +1,26 @@ | 
				
			||||
package rition.backend; | 
				
			||||
 | 
				
			||||
import com.github.yitter.contract.IdGeneratorOptions; | 
				
			||||
import com.github.yitter.idgen.YitIdHelper; | 
				
			||||
import org.mybatis.spring.annotation.MapperScan; | 
				
			||||
import org.springframework.boot.SpringApplication; | 
				
			||||
import org.springframework.boot.autoconfigure.SpringBootApplication; | 
				
			||||
import org.springframework.scheduling.annotation.EnableAsync; | 
				
			||||
import org.springframework.scheduling.annotation.EnableScheduling; | 
				
			||||
import org.springframework.transaction.annotation.EnableTransactionManagement; | 
				
			||||
 | 
				
			||||
@EnableAsync | 
				
			||||
@EnableScheduling | 
				
			||||
@SpringBootApplication | 
				
			||||
@SpringBootApplication(scanBasePackages = { | 
				
			||||
        "rition", | 
				
			||||
}) | 
				
			||||
@MapperScan("rition") | 
				
			||||
@EnableTransactionManagement | 
				
			||||
public class RitionBackendMain { | 
				
			||||
    public static void main(String[] args) { | 
				
			||||
        IdGeneratorOptions options = new IdGeneratorOptions((short) 0); | 
				
			||||
        YitIdHelper.setIdGenerator(options); | 
				
			||||
 | 
				
			||||
        SpringApplication.run(RitionBackendMain.class); | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
 | 
				
			||||
@ -0,0 +1,30 @@ | 
				
			||||
package rition.backend.service; | 
				
			||||
 | 
				
			||||
import org.springframework.stereotype.Service; | 
				
			||||
import rition.common.data.dto.MetricDataDto; | 
				
			||||
import rition.common.data.dto.MetricDataProto; | 
				
			||||
import rition.service.collector.MetricCollectingService; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * MetricCollectorService 指标数据收集类,负责收集来自云主机探针上报的数据,并将其入库等, | 
				
			||||
 * 这里只是个代理类,实际的实现在collector模块, | 
				
			||||
 * 这样做只是为了方便日后将collector等模块独立拆分出来, | 
				
			||||
 * 这种情况下实际上数据收集的入口应当直接放在collector里,而不是api部分 | 
				
			||||
 */ | 
				
			||||
@Service | 
				
			||||
public class MetricDataCollectingService { | 
				
			||||
 | 
				
			||||
    private final MetricCollectingService metricCollectingService; | 
				
			||||
 | 
				
			||||
    public MetricDataCollectingService(MetricCollectingService metricCollectingService) { | 
				
			||||
        this.metricCollectingService = metricCollectingService; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * 接收处理好的监控指标数据 | 
				
			||||
     * @param collectedMetricData 监控指标数据,protobuf对象 | 
				
			||||
     */ | 
				
			||||
    public void receiveData(MetricDataDto collectedMetricData) { | 
				
			||||
        metricCollectingService.receiveData(collectedMetricData); | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -1,2 +1,6 @@ | 
				
			||||
server: | 
				
			||||
  port: 22019 | 
				
			||||
 | 
				
			||||
spring: | 
				
			||||
  profiles: | 
				
			||||
    include: collector | 
				
			||||
@ -0,0 +1,48 @@ | 
				
			||||
 | 
				
			||||
package rition.common.data.dto; | 
				
			||||
 | 
				
			||||
import lombok.AllArgsConstructor; | 
				
			||||
import lombok.Builder; | 
				
			||||
import lombok.Data; | 
				
			||||
import lombok.NoArgsConstructor; | 
				
			||||
 | 
				
			||||
import java.util.List; | 
				
			||||
import java.util.Map; | 
				
			||||
 | 
				
			||||
@Data | 
				
			||||
@Builder | 
				
			||||
@NoArgsConstructor | 
				
			||||
@AllArgsConstructor | 
				
			||||
public class MetricDataDto { | 
				
			||||
 | 
				
			||||
    private List<MetricData> dataList; | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * 指标数据 | 
				
			||||
     */ | 
				
			||||
    @Data | 
				
			||||
    @Builder | 
				
			||||
    @NoArgsConstructor | 
				
			||||
    @AllArgsConstructor | 
				
			||||
    public static class MetricData { | 
				
			||||
        /** | 
				
			||||
         * 指标名 | 
				
			||||
         */ | 
				
			||||
        private String metric; | 
				
			||||
 | 
				
			||||
        /** | 
				
			||||
         * 数据标签 | 
				
			||||
         */ | 
				
			||||
        private Map<String, String> tags; | 
				
			||||
 | 
				
			||||
        /** | 
				
			||||
         * 时间戳 | 
				
			||||
         */ | 
				
			||||
        private Long timestamp; | 
				
			||||
 | 
				
			||||
        /** | 
				
			||||
         * 值 | 
				
			||||
         */ | 
				
			||||
        private String value; | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,17 @@ | 
				
			||||
package rition.common.data.enums; | 
				
			||||
 | 
				
			||||
import lombok.Getter; | 
				
			||||
 | 
				
			||||
@Getter | 
				
			||||
public enum CommonEntityStatus { | 
				
			||||
    STATUS_NORMAL(0), | 
				
			||||
    STATUS_DELETED(1), | 
				
			||||
    STATUS_HIDDEN(2), | 
				
			||||
    ; | 
				
			||||
 | 
				
			||||
    private final int value; | 
				
			||||
 | 
				
			||||
    CommonEntityStatus(int value) { | 
				
			||||
        this.value = value; | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,7 @@ | 
				
			||||
package rition.common.data.enums; | 
				
			||||
 | 
				
			||||
import java.time.ZoneId; | 
				
			||||
 | 
				
			||||
public class Constants { | 
				
			||||
    public static final ZoneId DefaultTimeZone = ZoneId.of("Asia/Shanghai"); | 
				
			||||
} | 
				
			||||
@ -0,0 +1,17 @@ | 
				
			||||
syntax = "proto3"; | 
				
			||||
 | 
				
			||||
package rition.proto.collecting.v1; | 
				
			||||
 | 
				
			||||
option java_package = "rition.common.data.dto"; | 
				
			||||
option java_outer_classname = "MetricDataProto"; | 
				
			||||
 | 
				
			||||
message MetricData { | 
				
			||||
  string metric = 1; | 
				
			||||
  string value = 2; | 
				
			||||
  uint64 timestamp = 3; | 
				
			||||
  map<string, string> tags = 4; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
message CollectedMetricData { | 
				
			||||
  repeated MetricData data = 4; | 
				
			||||
} | 
				
			||||
@ -1,4 +0,0 @@ | 
				
			||||
package rition.service.collector; | 
				
			||||
 | 
				
			||||
public class DataCollectorService { | 
				
			||||
} | 
				
			||||
@ -0,0 +1,94 @@ | 
				
			||||
package rition.service.collector; | 
				
			||||
 | 
				
			||||
import com.github.yitter.idgen.YitIdHelper; | 
				
			||||
import lombok.extern.slf4j.Slf4j; | 
				
			||||
import org.springframework.kafka.core.KafkaTemplate; | 
				
			||||
import org.springframework.stereotype.Service; | 
				
			||||
import rition.common.data.dto.MetricDataDto; | 
				
			||||
import rition.common.data.enums.CommonEntityStatus; | 
				
			||||
import rition.service.collector.configure.KafkaConfigure; | 
				
			||||
import rition.service.collector.dao.entity.MetricRecordEntity; | 
				
			||||
import rition.service.collector.dao.mapper.MetricRecordMapper; | 
				
			||||
 | 
				
			||||
import java.time.Instant; | 
				
			||||
import java.util.ArrayList; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * DataCollectorService 指标数据收集类,负责收集来自云主机探针上报的数据,并将其入库等 | 
				
			||||
 */ | 
				
			||||
@Slf4j | 
				
			||||
@Service | 
				
			||||
public class MetricCollectingService { | 
				
			||||
 | 
				
			||||
    private final KafkaTemplate<String, MetricDataDto> kafkaTemplate; | 
				
			||||
    private final KafkaConfigure kafkaConfigure; | 
				
			||||
 | 
				
			||||
    private final String collectedDataTopic; | 
				
			||||
    private final MetricRecordMapper metricRecordMapper; | 
				
			||||
 | 
				
			||||
    public MetricCollectingService(KafkaTemplate<String, MetricDataDto> kafkaTemplate, | 
				
			||||
                                   KafkaConfigure kafkaConfigure, MetricRecordMapper metricRecordMapper) { | 
				
			||||
        this.kafkaTemplate = kafkaTemplate; | 
				
			||||
        this.kafkaConfigure = kafkaConfigure; | 
				
			||||
        this.collectedDataTopic = kafkaConfigure.getDataCollecting().getTopic(); | 
				
			||||
        this.metricRecordMapper = metricRecordMapper; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    private static final int MAX_BATCH_INSERT_SIZE = 512; | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * 接收处理好的监控指标数据 | 
				
			||||
     * | 
				
			||||
     * @param collectedMetricData 监控指标数据,protobuf对象 | 
				
			||||
     */ | 
				
			||||
    public void receiveData(MetricDataDto collectedMetricData) { | 
				
			||||
        // 对大于MAX_BATCH_INSERT_SIZE大小的数据进行分组的批量插入
 | 
				
			||||
        var metricDataList = collectedMetricData.getDataList(); | 
				
			||||
        if (metricDataList.size() <= MAX_BATCH_INSERT_SIZE) { | 
				
			||||
            var metricRecordEntityList = new ArrayList<MetricRecordEntity>(metricDataList.size()); | 
				
			||||
            for (MetricDataDto.MetricData metricData : metricDataList) { | 
				
			||||
                MetricRecordEntity entity = this.convert(metricData); | 
				
			||||
 | 
				
			||||
                metricRecordEntityList.add(entity); | 
				
			||||
            } | 
				
			||||
 | 
				
			||||
            kafkaTemplate.send(this.collectedDataTopic, collectedMetricData); | 
				
			||||
            metricRecordMapper.insertBatchSomeColumn(metricRecordEntityList); | 
				
			||||
        } else { | 
				
			||||
            var batch = metricDataList.size() / MAX_BATCH_INSERT_SIZE; | 
				
			||||
            if (metricDataList.size() % MAX_BATCH_INSERT_SIZE != 0) { | 
				
			||||
                batch++; | 
				
			||||
            } | 
				
			||||
 | 
				
			||||
            var metricRecordEntityList = new ArrayList<MetricRecordEntity>(MAX_BATCH_INSERT_SIZE); | 
				
			||||
            for (int i = 0; i < batch; i++) { | 
				
			||||
                metricRecordEntityList.clear(); | 
				
			||||
                var from = i * MAX_BATCH_INSERT_SIZE; | 
				
			||||
                var to = (i + 1) * MAX_BATCH_INSERT_SIZE; | 
				
			||||
                var subList = metricDataList.subList(from, Math.min(metricDataList.size(), to)); | 
				
			||||
                for (MetricDataDto.MetricData metricData : subList) { | 
				
			||||
                    MetricRecordEntity entity = this.convert(metricData); | 
				
			||||
                    metricRecordEntityList.add(entity); | 
				
			||||
                } | 
				
			||||
 | 
				
			||||
                kafkaTemplate.send(this.collectedDataTopic, MetricDataDto.builder().dataList(subList).build()); | 
				
			||||
                metricRecordMapper.insertBatchSomeColumn(metricRecordEntityList); | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    public MetricRecordEntity convert(MetricDataDto.MetricData metricData) { | 
				
			||||
        MetricRecordEntity entity = new MetricRecordEntity(); | 
				
			||||
        entity.setId(YitIdHelper.nextId()); | 
				
			||||
        entity.setInstanceId(metricData.getTags().get("instanceId")); | 
				
			||||
        entity.setItem(metricData.getMetric()); | 
				
			||||
        entity.setValue(metricData.getValue()); | 
				
			||||
        entity.setStatus(CommonEntityStatus.STATUS_NORMAL.getValue()); | 
				
			||||
 | 
				
			||||
        var time = Instant.ofEpochMilli(metricData.getTimestamp()); | 
				
			||||
        entity.setTime(time); | 
				
			||||
        entity.setUpdateTime(time); | 
				
			||||
 | 
				
			||||
        return entity; | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,20 @@ | 
				
			||||
package rition.service.collector.configure; | 
				
			||||
 | 
				
			||||
import lombok.Data; | 
				
			||||
import org.springframework.boot.context.properties.ConfigurationProperties; | 
				
			||||
import org.springframework.context.annotation.Configuration; | 
				
			||||
 | 
				
			||||
@Data | 
				
			||||
@Configuration | 
				
			||||
@ConfigurationProperties("rition.kafka") | 
				
			||||
public class KafkaConfigure { | 
				
			||||
    private DataCollectingKafkaConfig dataCollecting; | 
				
			||||
 | 
				
			||||
    @Data | 
				
			||||
    public static class DataCollectingKafkaConfig { | 
				
			||||
        private String topic; | 
				
			||||
        private String group; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,8 @@ | 
				
			||||
package rition.service.collector.configure; | 
				
			||||
 | 
				
			||||
import org.springframework.context.annotation.Configuration; | 
				
			||||
 | 
				
			||||
@Configuration | 
				
			||||
public class MybatisPlusConfigure { | 
				
			||||
 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,21 @@ | 
				
			||||
package rition.service.collector.dao; | 
				
			||||
 | 
				
			||||
import com.baomidou.mybatisplus.core.injector.AbstractMethod; | 
				
			||||
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector; | 
				
			||||
import com.baomidou.mybatisplus.core.metadata.TableInfo; | 
				
			||||
import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn; | 
				
			||||
import org.apache.ibatis.session.Configuration; | 
				
			||||
import org.springframework.stereotype.Component; | 
				
			||||
 | 
				
			||||
import java.util.List; | 
				
			||||
 | 
				
			||||
@Component | 
				
			||||
public class BatchSQLInjector extends DefaultSqlInjector { | 
				
			||||
    @Override | 
				
			||||
    public List<AbstractMethod> getMethodList(Configuration configuration, Class<?> mapperClass, TableInfo tableInfo) { | 
				
			||||
        List<AbstractMethod> methodList = super.getMethodList(configuration, mapperClass, tableInfo); | 
				
			||||
        methodList.add(new InsertBatchSomeColumn()); | 
				
			||||
 | 
				
			||||
        return methodList; | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,59 @@ | 
				
			||||
package rition.service.collector.dao.entity; | 
				
			||||
 | 
				
			||||
import com.baomidou.mybatisplus.annotation.TableName; | 
				
			||||
import lombok.AllArgsConstructor; | 
				
			||||
import lombok.Builder; | 
				
			||||
import lombok.Data; | 
				
			||||
import lombok.NoArgsConstructor; | 
				
			||||
 | 
				
			||||
import java.time.Instant; | 
				
			||||
 | 
				
			||||
@Data | 
				
			||||
@Builder | 
				
			||||
@AllArgsConstructor | 
				
			||||
@NoArgsConstructor | 
				
			||||
@TableName("rition_record") | 
				
			||||
public class MetricRecordEntity { | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * 数据记录id | 
				
			||||
     */ | 
				
			||||
    private Long id; | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * 云主机实例id | 
				
			||||
     */ | 
				
			||||
    private String instanceId; | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * 数据项 | 
				
			||||
     */ | 
				
			||||
    private String item; | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * 数据值,统一使用字符串存储 | 
				
			||||
     */ | 
				
			||||
    private String value; | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * create_time | 
				
			||||
     */ | 
				
			||||
    private Instant time; | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * update_time | 
				
			||||
     */ | 
				
			||||
    private Instant updateTime; | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * status | 
				
			||||
     */ | 
				
			||||
    private Integer status; | 
				
			||||
 | 
				
			||||
    public static class RecordValueTypes { | 
				
			||||
        public static final int STRING = 0; | 
				
			||||
        public static final int INTEGER = 1; | 
				
			||||
        public static final int FLOAT = 2; | 
				
			||||
        public static final int BOOLEAN = 3; | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,12 @@ | 
				
			||||
package rition.service.collector.dao.mapper; | 
				
			||||
 | 
				
			||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; | 
				
			||||
import org.apache.ibatis.annotations.Mapper; | 
				
			||||
import rition.service.collector.dao.entity.MetricRecordEntity; | 
				
			||||
 | 
				
			||||
import java.util.List; | 
				
			||||
 | 
				
			||||
@Mapper | 
				
			||||
public interface MetricRecordMapper extends BaseMapper<MetricRecordEntity> { | 
				
			||||
    int insertBatchSomeColumn(List<MetricRecordEntity> entityList); | 
				
			||||
} | 
				
			||||
@ -0,0 +1,18 @@ | 
				
			||||
package rition.service.collector.mq; | 
				
			||||
 | 
				
			||||
import com.google.protobuf.InvalidProtocolBufferException; | 
				
			||||
import org.apache.kafka.common.serialization.Deserializer; | 
				
			||||
import rition.common.data.dto.MetricDataProto; | 
				
			||||
 | 
				
			||||
@Deprecated | 
				
			||||
public class CollectedMetricDataDeserializer implements Deserializer<MetricDataProto.CollectedMetricData> { | 
				
			||||
 | 
				
			||||
    @Override | 
				
			||||
    public MetricDataProto.CollectedMetricData deserialize(String topic, byte[] data) { | 
				
			||||
        try { | 
				
			||||
            return MetricDataProto.CollectedMetricData.parseFrom(data); | 
				
			||||
        } catch (InvalidProtocolBufferException e) { | 
				
			||||
            throw new RuntimeException("exception happen while parsing protobuf data: ", e); | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,13 @@ | 
				
			||||
package rition.service.collector.mq; | 
				
			||||
 | 
				
			||||
import com.google.protobuf.GeneratedMessageV3; | 
				
			||||
import org.apache.kafka.common.serialization.Serializer; | 
				
			||||
 | 
				
			||||
@Deprecated | 
				
			||||
public class ProtobufMessageSerializer implements Serializer<GeneratedMessageV3> { | 
				
			||||
 | 
				
			||||
    @Override | 
				
			||||
    public byte[] serialize(String topic, GeneratedMessageV3 data) { | 
				
			||||
        return data.toByteArray(); | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,19 @@ | 
				
			||||
spring: | 
				
			||||
  datasource: | 
				
			||||
    driver-class-name: com.mysql.cj.jdbc.Driver | 
				
			||||
    url: jdbc:mysql://127.0.0.1:3306/rition?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true | 
				
			||||
    username: root | 
				
			||||
    password: Test2333! | 
				
			||||
  kafka: | 
				
			||||
    bootstrap-servers: '127.0.0.1:9092' | 
				
			||||
    producer: | 
				
			||||
      retries: 4 | 
				
			||||
      compression-type: zstd | 
				
			||||
      key-serializer: org.apache.kafka.common.serialization.StringSerializer | 
				
			||||
      value-serializer: org.springframework.kafka.support.serializer.JsonSerializer | 
				
			||||
      acks: 1 | 
				
			||||
rition: | 
				
			||||
  kafka: | 
				
			||||
    data-collecting: | 
				
			||||
      topic: 'ecs-metric-data-topic' | 
				
			||||
      group: 'ecs-metric-data-group' | 
				
			||||
@ -0,0 +1,5 @@ | 
				
			||||
<?xml version="1.0" encoding="UTF-8" ?> | 
				
			||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > | 
				
			||||
<mapper namespace="rition.service.collector.dao.mapper.MetricRecordMapper"> | 
				
			||||
 | 
				
			||||
</mapper> | 
				
			||||
@ -1,16 +1,79 @@ | 
				
			||||
package client | 
				
			||||
 | 
				
			||||
import ( | 
				
			||||
	"bytes" | 
				
			||||
	"encoding/json" | 
				
			||||
	"fmt" | 
				
			||||
	"io" | 
				
			||||
	"net/http" | 
				
			||||
	"time" | 
				
			||||
) | 
				
			||||
 | 
				
			||||
type ReportDataItem struct { | 
				
			||||
	Metric    string            `json:"metric,omitempty"` | 
				
			||||
	Tags      map[string]string `json:"tags,omitempty"` | 
				
			||||
	Timestamp time.Time         `json:"timestamp"` | 
				
			||||
	Value     any               `json:"value,omitempty"` | 
				
			||||
	Tags      map[string]string `json:"tags,omitempty"` | 
				
			||||
	Timestamp int64             `json:"timestamp"` | 
				
			||||
} | 
				
			||||
 | 
				
			||||
type DataItem struct { | 
				
			||||
	Metric    string `json:"metric,omitempty"` | 
				
			||||
	Value     any    `json:"value,omitempty"` | 
				
			||||
	Timestamp int64  `json:"timestamp"` | 
				
			||||
} | 
				
			||||
 | 
				
			||||
func (c *Client) Report() { | 
				
			||||
type ReportResponse struct { | 
				
			||||
	RequestId string `json:"request_id,omitempty"` | 
				
			||||
	Message   string `json:"message,omitempty"` | 
				
			||||
} | 
				
			||||
 | 
				
			||||
func (c *Client) Report(dataItem []DataItem) (*ReportResponse, error) { | 
				
			||||
	tags := map[string]string{ | 
				
			||||
		"instanceId": c.config.InstanceId, | 
				
			||||
		"hostname":   c.config.HostName, | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	// convert data
 | 
				
			||||
	reportDataItems := make([]ReportDataItem, 0, len(dataItem)) | 
				
			||||
	for _, item := range dataItem { | 
				
			||||
		reportDataItems = append(reportDataItems, ReportDataItem{ | 
				
			||||
			Metric:    item.Metric, | 
				
			||||
			Value:     item.Value, | 
				
			||||
			Tags:      tags, | 
				
			||||
			Timestamp: time.Now().UnixMilli(), | 
				
			||||
		}) | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	reportJsonBytes, err := json.Marshal(reportDataItems) | 
				
			||||
	if err != nil { | 
				
			||||
		return nil, err | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	fmt.Println(string(reportJsonBytes)) | 
				
			||||
 | 
				
			||||
	// send report data
 | 
				
			||||
	resp, err := http.Post(c.config.CenterServer, "application/json", bytes.NewBuffer(reportJsonBytes)) | 
				
			||||
	if err != nil { | 
				
			||||
		return nil, err | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	// get response
 | 
				
			||||
	defer func(Body io.ReadCloser) { | 
				
			||||
		_ = Body.Close() | 
				
			||||
	}(resp.Body) | 
				
			||||
 | 
				
			||||
	respBytes, err := io.ReadAll(resp.Body) | 
				
			||||
	if err != nil { | 
				
			||||
		return nil, err | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	fmt.Println(string(respBytes)) | 
				
			||||
 | 
				
			||||
	response := ReportResponse{} | 
				
			||||
	err = json.Unmarshal(respBytes, &response) | 
				
			||||
	if err != nil { | 
				
			||||
		return nil, err | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	return &response, nil | 
				
			||||
} | 
				
			||||
 | 
				
			||||
@ -1,5 +1,37 @@ | 
				
			||||
package main | 
				
			||||
 | 
				
			||||
import ( | 
				
			||||
	"flag" | 
				
			||||
	"os" | 
				
			||||
	"rition-probe/client" | 
				
			||||
	"rition-probe/service" | 
				
			||||
	"time" | 
				
			||||
) | 
				
			||||
 | 
				
			||||
func main() { | 
				
			||||
	// --report '127.0.0.1:22019' --disk_dev nvme0n1 --mount / --net_dev wlp0s20f3 --interval 30
 | 
				
			||||
	centerServer := flag.String("report", "", "上报中心") | 
				
			||||
	diskDevice := flag.String("disk_dev", "", "监控的硬盘设备") | 
				
			||||
	mount := flag.String("mount", "/", "监控的分区挂载位置") | 
				
			||||
	netInterface := flag.String("net_dev", "", "监控的网卡设备") | 
				
			||||
	interval := flag.Int("interval", 30, "上报间隔,单位为秒") | 
				
			||||
	flag.Parse() | 
				
			||||
 | 
				
			||||
	hostname, _ := os.Hostname() | 
				
			||||
 | 
				
			||||
	config := service.Config{ | 
				
			||||
		ClientConfig: client.Config{ | 
				
			||||
			CenterServer: *centerServer, | 
				
			||||
			HostName:     hostname, | 
				
			||||
			InstanceId:   "5c4928f8-f27a-4ac9-85b4-c2dd03e086ad", | 
				
			||||
		}, | 
				
			||||
		MonitorDiskDevice:       *diskDevice, | 
				
			||||
		MonitorDiskMountPoint:   *mount, | 
				
			||||
		MonitorNetworkInterface: *netInterface, | 
				
			||||
		ReportInterval:          time.Duration(*interval) * time.Second, | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	srv := service.NewService(config) | 
				
			||||
	//srv.Run()
 | 
				
			||||
	srv.Report() | 
				
			||||
} | 
				
			||||
 | 
				
			||||
@ -0,0 +1,10 @@ | 
				
			||||
package probe | 
				
			||||
 | 
				
			||||
import ( | 
				
			||||
	"fmt" | 
				
			||||
	"testing" | 
				
			||||
) | 
				
			||||
 | 
				
			||||
func TestProbe_CurrentCPUTotalPercent(t *testing.T) { | 
				
			||||
	fmt.Println(probeTest.CurrentCPUTotalPercent()) | 
				
			||||
} | 
				
			||||
@ -0,0 +1,106 @@ | 
				
			||||
package service | 
				
			||||
 | 
				
			||||
import ( | 
				
			||||
	"fmt" | 
				
			||||
	"rition-probe/client" | 
				
			||||
	"time" | 
				
			||||
) | 
				
			||||
 | 
				
			||||
func (s *Service) Run() { | 
				
			||||
	ticker := time.NewTicker(s.config.ReportInterval) | 
				
			||||
	defer ticker.Stop() | 
				
			||||
 | 
				
			||||
	for range ticker.C { | 
				
			||||
		s.Report() | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
 | 
				
			||||
func (s *Service) Report() { | 
				
			||||
	dataItems := make([]client.DataItem, 0) | 
				
			||||
	nowTime := time.Now() | 
				
			||||
	now := nowTime.UnixMilli() | 
				
			||||
 | 
				
			||||
	// cpu
 | 
				
			||||
	_5minCPULoad := s.prevCpuLoadData | 
				
			||||
	if nowTime.Sub(s.prevCpuLoadDataCollectTime).Minutes() >= 5 { | 
				
			||||
		_5minCPULoad = s.probe.CurrentCPUTotalPercent() | 
				
			||||
	} | 
				
			||||
	dataItems = append(dataItems, client.DataItem{ | 
				
			||||
		Metric:    "node_load5", | 
				
			||||
		Value:     _5minCPULoad, | 
				
			||||
		Timestamp: now, | 
				
			||||
	}) | 
				
			||||
 | 
				
			||||
	sysUptime := s.probe.HostUptime() | 
				
			||||
	dataItems = append(dataItems, client.DataItem{ | 
				
			||||
		Metric:    "node_cpu_seconds_total", | 
				
			||||
		Value:     sysUptime, | 
				
			||||
		Timestamp: now, | 
				
			||||
	}) | 
				
			||||
 | 
				
			||||
	// mem
 | 
				
			||||
	memTotal, memUsed, memBuffers, memCached := s.probe.RamUsage() | 
				
			||||
	dataItems = append(dataItems, client.DataItem{ | 
				
			||||
		Metric: "node_memory_MemTotal_bytes", Value: memTotal, Timestamp: now, | 
				
			||||
	}, client.DataItem{ | 
				
			||||
		Metric: "node_memory_MemFree_bytes", Value: memTotal - memUsed, Timestamp: now, | 
				
			||||
	}, client.DataItem{ | 
				
			||||
		Metric: "node_memory_Buffers_bytes", Value: memBuffers, Timestamp: now, | 
				
			||||
	}, client.DataItem{ | 
				
			||||
		Metric: "node_memory_Cached_bytes", Value: memCached, Timestamp: now, | 
				
			||||
	}) | 
				
			||||
 | 
				
			||||
	// disk
 | 
				
			||||
	usageStat, diskIoCount := s.probe.DiskStatus(s.config.MonitorDiskMountPoint, s.config.MonitorDiskDevice) | 
				
			||||
	dataItems = append(dataItems, client.DataItem{ | 
				
			||||
		Metric: "node_filesystem_avail_bytes", Value: usageStat.Free, Timestamp: now, | 
				
			||||
	}, client.DataItem{ | 
				
			||||
		Metric: "node_filesystem_size_bytes", Value: usageStat.Total, Timestamp: now, | 
				
			||||
	}, client.DataItem{ | 
				
			||||
		Metric: "node_filesystem_free_bytes", Value: usageStat.Free, Timestamp: now, | 
				
			||||
	}, client.DataItem{ | 
				
			||||
		Metric: "node_disk_read_bytes_total", Value: diskIoCount.ReadBytes, Timestamp: now, | 
				
			||||
	}, client.DataItem{ | 
				
			||||
		Metric: "node_disk_written_bytes_total", Value: diskIoCount.WriteBytes, Timestamp: now, | 
				
			||||
	}, client.DataItem{ | 
				
			||||
		Metric: "node_disk_reads_completed_total", Value: diskIoCount.MergedWriteCount, Timestamp: now, | 
				
			||||
	}, client.DataItem{ | 
				
			||||
		Metric: "node_disk_writes_completed_total", Value: diskIoCount.MergedWriteCount, Timestamp: now, | 
				
			||||
	}) | 
				
			||||
 | 
				
			||||
	// network
 | 
				
			||||
	networkIoCount, conns := s.probe.GetNetworkCounterOne(s.config.MonitorNetworkInterface) | 
				
			||||
	dataItems = append(dataItems, client.DataItem{ | 
				
			||||
		Metric: "node_network_receive_bytes_total", Value: networkIoCount.BytesRecv, Timestamp: now, | 
				
			||||
	}, client.DataItem{ | 
				
			||||
		Metric: "node_network_transmit_bytes_total", Value: networkIoCount.BytesSent, Timestamp: now, | 
				
			||||
	}, client.DataItem{ | 
				
			||||
		Metric: "node_network_receive_packets_total", Value: networkIoCount.PacketsRecv, Timestamp: now, | 
				
			||||
	}, client.DataItem{ | 
				
			||||
		Metric: "node_network_transmit_packets_total", Value: networkIoCount.PacketsSent, Timestamp: now, | 
				
			||||
	}, client.DataItem{ | 
				
			||||
		Metric: "node_network_receive_drop_total", Value: networkIoCount.Dropin, Timestamp: now, | 
				
			||||
	}, client.DataItem{ | 
				
			||||
		Metric: "node_network_transmit_drop_total", Value: networkIoCount.Dropout, Timestamp: now, | 
				
			||||
	}) | 
				
			||||
 | 
				
			||||
	estabCnt, twCnt := 0, 0 | 
				
			||||
	for _, conn := range conns { | 
				
			||||
		switch conn.Status { | 
				
			||||
		case "ESTABLISHED": | 
				
			||||
			estabCnt++ | 
				
			||||
		case "TIME_WAIT": | 
				
			||||
			twCnt++ | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
	dataItems = append(dataItems, client.DataItem{ | 
				
			||||
		Metric: "node_netstat_Tcp_CurrEstab", Value: estabCnt, Timestamp: now, | 
				
			||||
	}, client.DataItem{ | 
				
			||||
		Metric: "node_netstat_Tcp_tw", Value: twCnt, Timestamp: now, | 
				
			||||
	}) | 
				
			||||
 | 
				
			||||
	_, err := s.client.Report(dataItems) | 
				
			||||
	if err != nil { | 
				
			||||
		fmt.Println("err: ", err.Error()) | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
@ -1,22 +1,38 @@ | 
				
			||||
package service | 
				
			||||
 | 
				
			||||
import "time" | 
				
			||||
import ( | 
				
			||||
	"rition-probe/client" | 
				
			||||
	"rition-probe/probe" | 
				
			||||
	"time" | 
				
			||||
) | 
				
			||||
 | 
				
			||||
type Config struct { | 
				
			||||
	CenterServer   string        `json:"centerServer,omitempty"` | 
				
			||||
	HostName       string        `json:"hostName,omitempty"` | 
				
			||||
	InstanceId     string        `json:"instanceId,omitempty"` | 
				
			||||
	ClientConfig            client.Config | 
				
			||||
	MonitorDiskDevice       string | 
				
			||||
	MonitorDiskMountPoint   string | 
				
			||||
	MonitorNetworkInterface string | 
				
			||||
 | 
				
			||||
	ReportInterval time.Duration `json:"reportInterval,omitempty"` | 
				
			||||
} | 
				
			||||
 | 
				
			||||
type Service struct { | 
				
			||||
	config Config | 
				
			||||
	probe  *probe.Probe | 
				
			||||
	client *client.Client | 
				
			||||
 | 
				
			||||
	prevCpuLoadDataCollectTime time.Time | 
				
			||||
	prevCpuLoadData            float64 | 
				
			||||
} | 
				
			||||
 | 
				
			||||
func NewService(config Config) *Service { | 
				
			||||
	service := Service{ | 
				
			||||
		config: config, | 
				
			||||
		probe:  probe.NewProbe(), | 
				
			||||
		client: client.NetClient(config.ClientConfig), | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	service.prevCpuLoadData = service.probe.CurrentCPUTotalPercent() | 
				
			||||
	service.prevCpuLoadDataCollectTime = time.Now() | 
				
			||||
 | 
				
			||||
	return &service | 
				
			||||
} | 
				
			||||
 | 
				
			||||
					Loading…
					
					
				
		Reference in new issue