github.com/GuanceCloud/cliutils@v1.1.21/point/p8s_point.go (about) 1 // Unless explicitly stated otherwise all files in this repository are licensed 2 // under the MIT License. 3 // This product includes software developed at Guance Cloud (https://www.guance.com/). 4 // Copyright 2021-present Guance, Inc. 5 6 package point 7 8 import ( 9 "strings" 10 "time" 11 12 "github.com/prometheus/client_golang/prometheus" 13 dto "github.com/prometheus/client_model/go" 14 ) 15 16 // mergePts merge pts when: 17 // 18 // - they got same measurement name 19 // 20 // - they got same tag key and tag values 21 // 22 // - they got same time(nano-second) 23 // 24 // NOTE: you should ensure that these time is equal, point's hash not 25 // covered the time field. For prometheus metrics, these time value are 26 // the same. 27 // 28 // When point.Point are logging, due to the lack of `time-series', 29 // we hava to merge multiple points' fields together to build a single point. 30 // 31 // For time-series data, we don't need to do this, the storage 32 // engine merged them automatically(grouped by time-series). 33 func mergePts(pts []*Point) []*Point { 34 // same-hash point put together 35 var res []*Point 36 ptMap := map[string][]*Point{} 37 for _, pt := range pts { 38 hash := pt.MD5() 39 ptMap[hash] = append(ptMap[hash], pt) 40 } 41 42 for _, pts := range ptMap { 43 if len(pts) > 1 { 44 // merge all points(with same hash) fields to the first one. 45 for i := 1; i < len(pts); i++ { 46 fs := pts[i].Fields() 47 for _, f := range fs { 48 pts[0].AddKVs(f) 49 } 50 } 51 52 // keep the first point, drop all merged points. 53 res = append(res, pts[0]) 54 } 55 } 56 57 return res 58 } 59 60 func doGatherPoints(reg prometheus.Gatherer) ([]*Point, error) { 61 mfs, err := reg.Gather() 62 if err != nil { 63 return nil, err 64 } 65 66 // All gathered data should have the same timestamp, we enforce it. 67 now := time.Now() 68 69 var pts []*Point 70 for _, mf := range mfs { 71 arr := strings.SplitN(*mf.Name, "_", 2) 72 73 name := arr[0] 74 fieldName := arr[1] 75 76 for _, m := range mf.Metric { 77 var kvs KVs 78 for _, label := range m.GetLabel() { 79 kvs = append(kvs, NewKV(label.GetName(), label.GetValue(), WithKVTagSet(true))) 80 } 81 82 switch *mf.Type { 83 case dto.MetricType_COUNTER: 84 kvs = append(kvs, NewKV(fieldName, m.GetCounter().GetValue())) 85 case dto.MetricType_SUMMARY: 86 avg := uint64(m.GetSummary().GetSampleSum()) / m.GetSummary().GetSampleCount() 87 kvs = append(kvs, NewKV(fieldName, avg)) 88 89 case dto.MetricType_GAUGE: 90 continue // TODO 91 case dto.MetricType_HISTOGRAM: 92 continue // TODO 93 case dto.MetricType_UNTYPED: 94 continue // TODO 95 case dto.MetricType_GAUGE_HISTOGRAM: 96 continue // TODO 97 } 98 99 // TODO: according to specific tags, we should make them as logging. 100 ts := now 101 if m.TimestampMs != nil { // use metric time 102 ts = time.Unix(0, int64(time.Millisecond)**m.TimestampMs) 103 } 104 105 opts := append(DefaultMetricOptions(), WithTime(ts)) 106 pts = append(pts, NewPointV2(name, kvs, opts...)) 107 } 108 } 109 110 return pts, nil 111 } 112 113 // GatherPoints gather all metrics in global registry, but convert these metrics 114 // to Point. 115 func GatherPoints(reg prometheus.Gatherer) ([]*Point, error) { 116 return doGatherPoints(reg) 117 }