github.com/alibaba/ilogtail/pkg@v0.0.0-20250526110833-c53b480d046c/protocol/encoder/prometheus/utils.go (about) 1 // Copyright 2024 iLogtail Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package prometheus 16 17 import ( 18 "context" 19 "sort" 20 "sync" 21 22 pb "github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal" 23 24 "github.com/alibaba/ilogtail/pkg/logger" 25 "github.com/alibaba/ilogtail/pkg/models" 26 ) 27 28 const metricNameKey = "__name__" 29 30 func marshalBatchTimeseriesData(wr *pb.WriteRequest) []byte { 31 if len(wr.Timeseries) == 0 { 32 return nil 33 } 34 35 data, err := wr.Marshal() 36 if err != nil { 37 // logger.Error(context.Background(), alarmType, "pb marshal err", err) 38 return nil 39 } 40 41 return data 42 } 43 44 func genPromRemoteWriteTimeseries(event *models.Metric) pb.TimeSeries { 45 return pb.TimeSeries{ 46 Labels: lexicographicalSort(append(convTagsToLabels(event.GetTags()), pb.Label{Name: metricNameKey, Value: event.GetName()})), 47 Samples: []pb.Sample{{ 48 Value: event.GetValue().GetSingleValue(), 49 50 // Decode (during input_prometheus stage) makes timestamp 51 // with unix milliseconds into unix nanoseconds, 52 // e.g. "model.Time(milliseconds).Time().UnixNano()". 53 // 54 // Encode (during flusher_prometheus stage) conversely makes timestamp 55 // with unix nanoseconds into unix milliseconds, 56 // e.g. "int64(nanoseconds)/10^6". 57 Timestamp: int64(event.GetTimestamp()) / 1e6, 58 }}, 59 } 60 } 61 62 func convTagsToLabels(tags models.Tags) []pb.Label { 63 if tags == nil { 64 logger.Debugf(context.Background(), "get nil models.Tags") 65 return nil 66 } 67 68 labels := make([]pb.Label, 0, tags.Len()) 69 for k, v := range tags.Iterator() { 70 // MUST NOT contain any empty label names or values. 71 // reference: https://prometheus.io/docs/specs/remote_write_spec/#labels 72 if k != "" && v != "" { 73 labels = append(labels, pb.Label{Name: k, Value: v}) 74 } 75 } 76 77 return labels 78 } 79 80 // MUST have label names sorted in lexicographical order. 81 // reference: https://prometheus.io/docs/specs/remote_write_spec/#labels 82 func lexicographicalSort(labels []pb.Label) []pb.Label { 83 sort.Sort(promLabels(labels)) 84 85 return labels 86 } 87 88 type promLabels []pb.Label 89 90 func (p promLabels) Len() int { 91 return len(p) 92 } 93 94 func (p promLabels) Less(i, j int) bool { 95 return p[i].Name < p[j].Name 96 } 97 98 func (p promLabels) Swap(i, j int) { 99 p[i], p[j] = p[j], p[i] 100 } 101 102 var wrPool sync.Pool 103 104 func getWriteRequest(seriesLimit int) *pb.WriteRequest { 105 wr := wrPool.Get() 106 if wr == nil { 107 return &pb.WriteRequest{ 108 Timeseries: make([]pb.TimeSeries, 0, seriesLimit), 109 } 110 } 111 112 return wr.(*pb.WriteRequest) 113 } 114 115 func putWriteRequest(wr *pb.WriteRequest) { 116 wr.Timeseries = wr.Timeseries[:0] 117 wrPool.Put(wr) 118 }