searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

基于反射实现面向对象的数据采集

2024-11-13 09:32:02
0
0

1、定义数据采集实体类

首先如下定义数据采集实体类,其中用metricName注解来标识最终的指标名称,promValueType用来标识采集的数据类型。值得注意的是用*float为类型来表示数据的结果,可能存在部分指标没有情况下,如果使用float无法正确识别数据是否为空。

type Client struct {
	ProcessCpu       *float64 `metricName:"ClientProcessCpu" promValueType:"Gauge"`
	SystemCpu        *float64 `metricName:"ClientSystemCpu" promValueType:"Gauge"`
}

通过下列方法,判断数据中是否需要将该指标暴露,并且统一成PromValueRes的方式进行数据返回

func GetPromValueRes(param interface{}) []PromValueRes {
	t := reflect.TypeOf(param)
	v := reflect.ValueOf(param)
	resList := []PromValueRes{}
	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		var valueType prometheus.ValueType
		promValueType := field.Tag.Get("promValueType")
		switch promValueType {
		case "Gauge":
			valueType = prometheus.GaugeValue
		case "Counter":
			valueType = prometheus.CounterValue
		default:
			valueType = prometheus.UntypedValue
		}
		metricName := field.Tag.Get("metricName")
		if metricName == "" || metricName == "-" {
			// metricName为空
			continue
		}
		val := v.Field(i)
		// 判断字段是否赋值
		zero := reflect.Zero(reflect.TypeOf(val.Interface()))
		if reflect.DeepEqual(val.Interface(), zero.Interface()) {
			// 字段为空
			continue
		}
		valf := val.Elem().Float()
		resList = append(resList, PromValueRes{
			MetricName: metricName,
			ValueType:  valueType,
			Value:      valf,
		})
	}
	return resList
}
type PromValueRes struct {
	MetricName string
	ValueType  prometheus.ValueType
	Value      float64
}

2、标签处理

同理的,可以对标签也用对象抽象,如下,使用promLabel标识标签数据名称

type ClientLabel struct {
	Os           string `promLabel:"os"`
	Ver          string `promLabel:"ver"`
    Ip 			 string `promLabel:"ip"`
}

通过下列方法获取分别获取指标名称,和对应指标值

func GetPromLabelName(param interface{}) []string {
	ss := []string{}
	t := reflect.TypeOf(param)
	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		tag := field.Tag.Get("promLabel")
		if tag != "" {
			ss = append(ss, tag)
		}
	}
	return ss
}

func GetPromLabelValue(param interface{}) []string {
	ss := []string{}
	v := reflect.ValueOf(param)
	t := reflect.TypeOf(param)
	for i := 0; i < v.NumField(); i++ {
		val := v.Field(i)
		field := t.Field(i)
		tag := field.Tag.Get("promLabel")
		if tag != "" {
			ss = append(ss, val.String())
		}
	}
	return ss
}

3、数据转化

通过上述两个步骤中反射的方法,我们获取Client{}这个类对应的指标数据和标签名称ClientLabel{}

再对两份数据进行处理,得到最终可以上报接口数据如下:

type PromMetric struct {
	Label PromLabel
	Value PromValue
	// 毫秒
	Ts int64
}
type PromLabel interface {
	GetLabelName() []string
	GetLabelValue() []string
}

type PromValue interface {
	GetPromValue() []PromValueRes
}
func (e *Exporter) consumer(ch chan<- prometheus.Metric) {
    pm := model.PromMetric{
        Label: ClientLabel{
            Os: "windows",
            Ver: "1.0.0",
            Ip: "127.0.0.1",
        },
        Value: Client{
            ProcessCpu: 86.7,
            SystemCpu: 59.1,
        },
        Ts: 1731464540,
    }
    labels := pm.Label.GetLabelValue()
    tm := time.UnixMilli(pm.Ts)
    for _, res := range pm.Value.GetPromValue() {
        metricName := res.MetricName
        if desc, ok := e.metrics[metricName]; ok {
            ch <- prometheus.NewMetricWithTimestamp(
                tm,
                prometheus.MustNewConstMetric(
                    desc, res.ValueType, res.Value, labels...,
                ),
            )
        }
    }
}

最终得到Prometheus格式数据如下:

ProcessCpu{Os="windows", Ver="1.0.0", Ip="127.0.0.1"} 86.7

SystemCpu{Os="windows", Ver="1.0.0", Ip="127.0.0.1"} 59.1
0条评论
0 / 1000
吴溢豪
5文章数
0粉丝数
吴溢豪
5 文章 | 0 粉丝
原创

基于反射实现面向对象的数据采集

2024-11-13 09:32:02
0
0

1、定义数据采集实体类

首先如下定义数据采集实体类,其中用metricName注解来标识最终的指标名称,promValueType用来标识采集的数据类型。值得注意的是用*float为类型来表示数据的结果,可能存在部分指标没有情况下,如果使用float无法正确识别数据是否为空。

type Client struct {
	ProcessCpu       *float64 `metricName:"ClientProcessCpu" promValueType:"Gauge"`
	SystemCpu        *float64 `metricName:"ClientSystemCpu" promValueType:"Gauge"`
}

通过下列方法,判断数据中是否需要将该指标暴露,并且统一成PromValueRes的方式进行数据返回

func GetPromValueRes(param interface{}) []PromValueRes {
	t := reflect.TypeOf(param)
	v := reflect.ValueOf(param)
	resList := []PromValueRes{}
	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		var valueType prometheus.ValueType
		promValueType := field.Tag.Get("promValueType")
		switch promValueType {
		case "Gauge":
			valueType = prometheus.GaugeValue
		case "Counter":
			valueType = prometheus.CounterValue
		default:
			valueType = prometheus.UntypedValue
		}
		metricName := field.Tag.Get("metricName")
		if metricName == "" || metricName == "-" {
			// metricName为空
			continue
		}
		val := v.Field(i)
		// 判断字段是否赋值
		zero := reflect.Zero(reflect.TypeOf(val.Interface()))
		if reflect.DeepEqual(val.Interface(), zero.Interface()) {
			// 字段为空
			continue
		}
		valf := val.Elem().Float()
		resList = append(resList, PromValueRes{
			MetricName: metricName,
			ValueType:  valueType,
			Value:      valf,
		})
	}
	return resList
}
type PromValueRes struct {
	MetricName string
	ValueType  prometheus.ValueType
	Value      float64
}

2、标签处理

同理的,可以对标签也用对象抽象,如下,使用promLabel标识标签数据名称

type ClientLabel struct {
	Os           string `promLabel:"os"`
	Ver          string `promLabel:"ver"`
    Ip 			 string `promLabel:"ip"`
}

通过下列方法获取分别获取指标名称,和对应指标值

func GetPromLabelName(param interface{}) []string {
	ss := []string{}
	t := reflect.TypeOf(param)
	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		tag := field.Tag.Get("promLabel")
		if tag != "" {
			ss = append(ss, tag)
		}
	}
	return ss
}

func GetPromLabelValue(param interface{}) []string {
	ss := []string{}
	v := reflect.ValueOf(param)
	t := reflect.TypeOf(param)
	for i := 0; i < v.NumField(); i++ {
		val := v.Field(i)
		field := t.Field(i)
		tag := field.Tag.Get("promLabel")
		if tag != "" {
			ss = append(ss, val.String())
		}
	}
	return ss
}

3、数据转化

通过上述两个步骤中反射的方法,我们获取Client{}这个类对应的指标数据和标签名称ClientLabel{}

再对两份数据进行处理,得到最终可以上报接口数据如下:

type PromMetric struct {
	Label PromLabel
	Value PromValue
	// 毫秒
	Ts int64
}
type PromLabel interface {
	GetLabelName() []string
	GetLabelValue() []string
}

type PromValue interface {
	GetPromValue() []PromValueRes
}
func (e *Exporter) consumer(ch chan<- prometheus.Metric) {
    pm := model.PromMetric{
        Label: ClientLabel{
            Os: "windows",
            Ver: "1.0.0",
            Ip: "127.0.0.1",
        },
        Value: Client{
            ProcessCpu: 86.7,
            SystemCpu: 59.1,
        },
        Ts: 1731464540,
    }
    labels := pm.Label.GetLabelValue()
    tm := time.UnixMilli(pm.Ts)
    for _, res := range pm.Value.GetPromValue() {
        metricName := res.MetricName
        if desc, ok := e.metrics[metricName]; ok {
            ch <- prometheus.NewMetricWithTimestamp(
                tm,
                prometheus.MustNewConstMetric(
                    desc, res.ValueType, res.Value, labels...,
                ),
            )
        }
    }
}

最终得到Prometheus格式数据如下:

ProcessCpu{Os="windows", Ver="1.0.0", Ip="127.0.0.1"} 86.7

SystemCpu{Os="windows", Ver="1.0.0", Ip="127.0.0.1"} 59.1
文章来自个人专栏
golang编程
2 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0