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  }