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  }