github.com/alibaba/ilogtail/pkg@v0.0.0-20250526110833-c53b480d046c/protocol/converter/converter_sls_metric.go (about) 1 // Copyright 2022 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 protocol 16 17 import ( 18 "fmt" 19 "sort" 20 "strconv" 21 "strings" 22 "sync" 23 "time" 24 25 "github.com/alibaba/ilogtail/pkg/protocol" 26 ) 27 28 const ( 29 metricNameKey = "__name__" 30 metricLabelsKey = "__labels__" 31 metricTimeNanoKey = "__time_nano__" 32 metricValueKey = "__value__" 33 metricValueTypeKey = "__type__" 34 metricFieldKey = "__field__" 35 ) 36 37 const ( 38 valueTypeFloat = "float" 39 valueTypeInt = "int" 40 valueTypeBool = "bool" 41 valueTypeString = "string" 42 ) 43 44 const ( 45 KeyValueSeparator = "#$#" 46 LabelSeparator = "|" 47 ) 48 49 var readerPool = sync.Pool{ 50 New: func() any { 51 return &metricReader{} 52 }, 53 } 54 55 type metricReader struct { 56 name string 57 labels string 58 value string 59 valueType string 60 timestamp string 61 fieldName string 62 } 63 64 type MetricLabel struct { 65 Key string 66 Value string 67 } 68 69 type MetricLabels []MetricLabel 70 71 func (m MetricLabels) Len() int { 72 return len(m) 73 } 74 75 func (m MetricLabels) Less(i, j int) bool { 76 return m[i].Key < m[j].Key 77 } 78 79 func (m MetricLabels) Swap(i, j int) { 80 m[i], m[j] = m[j], m[i] 81 } 82 83 func (m MetricLabels) GetLabel() string { 84 // sort label 85 sort.Sort(m) 86 var res []string 87 for _, label := range m { 88 res = append(res, label.Key+KeyValueSeparator+label.Value) 89 } 90 return strings.Join(res, LabelSeparator) 91 } 92 93 func (r *metricReader) readNames() (metricName, fieldName string) { 94 if len(r.fieldName) == 0 || r.fieldName == "value" { 95 return r.name, "value" 96 } 97 name := strings.TrimSuffix(r.name, ":"+r.fieldName) 98 return name, r.fieldName 99 } 100 101 func (r *metricReader) readSortedLabels() ([]MetricLabel, error) { 102 n := r.countLabels() 103 if n == 0 { 104 return nil, nil 105 } 106 107 labels := make([]MetricLabel, 0, n) 108 remainLabels := r.labels 109 lastIndex := -1 110 label := "" 111 key := "" 112 113 for len(remainLabels) > 0 { 114 endIdx := strings.Index(remainLabels, "|") 115 if endIdx < 0 { 116 label = remainLabels 117 remainLabels = "" 118 } else { 119 label = remainLabels[:endIdx] 120 remainLabels = remainLabels[endIdx+1:] 121 } 122 splitIdx := strings.Index(label, "#$#") 123 if splitIdx < 0 { 124 if lastIndex >= 0 { 125 labels[lastIndex].Value += "|" 126 labels[lastIndex].Value += label 127 continue 128 } 129 if len(key) == 0 { 130 key = label 131 continue 132 } 133 key += "|" 134 key += label 135 continue 136 } 137 138 if len(key) > 0 { 139 key += "|" 140 key += label[:splitIdx] 141 } else { 142 key = label[:splitIdx] 143 } 144 145 labels = append(labels, MetricLabel{Key: key, Value: label[splitIdx+3:]}) 146 147 lastIndex++ 148 key = "" 149 150 if endIdx < 0 { 151 break 152 } 153 } 154 155 sort.Sort(MetricLabels(labels)) 156 157 if len(key) > 0 { 158 return labels, fmt.Errorf("found miss matching key: %s", key) 159 } 160 161 return labels, nil 162 } 163 164 func (r *metricReader) countLabels() int { 165 if len(r.labels) == 0 { 166 return 0 167 } 168 n := strings.Count(r.labels, "|") 169 return n + 1 170 } 171 172 func (r *metricReader) readValue() (interface{}, error) { 173 switch r.valueType { 174 case valueTypeBool: 175 return strconv.ParseBool(r.value) 176 case valueTypeString: 177 return r.value, nil 178 case valueTypeInt: 179 return strconv.ParseInt(r.value, 10, 64) 180 default: 181 return strconv.ParseFloat(r.value, 64) 182 } 183 } 184 185 func (r *metricReader) readTimestamp() (time.Time, error) { 186 187 if len(r.timestamp) == 0 { 188 return time.Time{}, nil 189 } 190 t, err := strconv.ParseInt(r.timestamp, 10, 64) 191 if err != nil { 192 return time.Time{}, err 193 } 194 return time.Unix(t/1e9, t%1e9).UTC(), nil 195 } 196 197 func (r *metricReader) recycle() { 198 r.reset() 199 readerPool.Put(r) 200 } 201 202 func (r *metricReader) reset() { 203 r.labels = "" 204 r.name = "" 205 r.value = "" 206 r.valueType = "" 207 r.timestamp = "" 208 r.fieldName = "" 209 } 210 211 func (r *metricReader) set(log *protocol.Log) error { 212 r.reset() 213 for _, v := range log.Contents { 214 switch v.Key { 215 case metricNameKey: 216 r.name = v.Value 217 case metricLabelsKey: 218 r.labels = v.Value 219 case metricTimeNanoKey: 220 r.timestamp = v.Value 221 case metricValueKey: 222 r.value = v.Value 223 case metricValueTypeKey: 224 r.valueType = v.Value 225 case metricFieldKey: 226 r.fieldName = v.Value 227 } 228 } 229 if len(r.name) == 0 || len(r.value) == 0 && r.valueType != valueTypeString { 230 return fmt.Errorf("metrics data must contains keys: %s, %s", metricNameKey, metricValueKey) 231 } 232 return nil 233 } 234 235 func newMetricReader() *metricReader { 236 return readerPool.Get().(*metricReader) 237 }