github.com/muhammadn/cortex@v1.9.1-0.20220510110439-46bb7000d03d/pkg/util/validation/errors.go (about) 1 package validation 2 3 import ( 4 "fmt" 5 "strconv" 6 "strings" 7 8 "github.com/prometheus/common/model" 9 10 "github.com/cortexproject/cortex/pkg/cortexpb" 11 ) 12 13 // ValidationError is an error returned by series validation. 14 // 15 // nolint:golint ignore stutter warning 16 type ValidationError error 17 18 // genericValidationError is a basic implementation of ValidationError which can be used when the 19 // error format only contains the cause and the series. 20 type genericValidationError struct { 21 message string 22 cause string 23 series []cortexpb.LabelAdapter 24 } 25 26 func (e *genericValidationError) Error() string { 27 return fmt.Sprintf(e.message, e.cause, formatLabelSet(e.series)) 28 } 29 30 func newLabelNameTooLongError(series []cortexpb.LabelAdapter, labelName string) ValidationError { 31 return &genericValidationError{ 32 message: "label name too long: %.200q metric %.200q", 33 cause: labelName, 34 series: series, 35 } 36 } 37 38 // labelValueTooLongError is a customized ValidationError, in that the cause and the series are 39 // are formatted in different order in Error. 40 type labelValueTooLongError struct { 41 labelValue string 42 series []cortexpb.LabelAdapter 43 } 44 45 func (e *labelValueTooLongError) Error() string { 46 return fmt.Sprintf("label value too long for metric: %.200q label value: %.200q", formatLabelSet(e.series), e.labelValue) 47 } 48 49 func newLabelValueTooLongError(series []cortexpb.LabelAdapter, labelValue string) ValidationError { 50 return &labelValueTooLongError{ 51 labelValue: labelValue, 52 series: series, 53 } 54 } 55 56 func newInvalidLabelError(series []cortexpb.LabelAdapter, labelName string) ValidationError { 57 return &genericValidationError{ 58 message: "sample invalid label: %.200q metric %.200q", 59 cause: labelName, 60 series: series, 61 } 62 } 63 64 func newDuplicatedLabelError(series []cortexpb.LabelAdapter, labelName string) ValidationError { 65 return &genericValidationError{ 66 message: "duplicate label name: %.200q metric %.200q", 67 cause: labelName, 68 series: series, 69 } 70 } 71 72 func newLabelsNotSortedError(series []cortexpb.LabelAdapter, labelName string) ValidationError { 73 return &genericValidationError{ 74 message: "labels not sorted: %.200q metric %.200q", 75 cause: labelName, 76 series: series, 77 } 78 } 79 80 type tooManyLabelsError struct { 81 series []cortexpb.LabelAdapter 82 limit int 83 } 84 85 func newTooManyLabelsError(series []cortexpb.LabelAdapter, limit int) ValidationError { 86 return &tooManyLabelsError{ 87 series: series, 88 limit: limit, 89 } 90 } 91 92 func (e *tooManyLabelsError) Error() string { 93 return fmt.Sprintf( 94 "series has too many labels (actual: %d, limit: %d) series: '%s'", 95 len(e.series), e.limit, cortexpb.FromLabelAdaptersToMetric(e.series).String()) 96 } 97 98 type noMetricNameError struct{} 99 100 func newNoMetricNameError() ValidationError { 101 return &noMetricNameError{} 102 } 103 104 func (e *noMetricNameError) Error() string { 105 return "sample missing metric name" 106 } 107 108 type invalidMetricNameError struct { 109 metricName string 110 } 111 112 func newInvalidMetricNameError(metricName string) ValidationError { 113 return &invalidMetricNameError{ 114 metricName: metricName, 115 } 116 } 117 118 func (e *invalidMetricNameError) Error() string { 119 return fmt.Sprintf("sample invalid metric name: %.200q", e.metricName) 120 } 121 122 // sampleValidationError is a ValidationError implementation suitable for sample validation errors. 123 type sampleValidationError struct { 124 message string 125 metricName string 126 timestamp int64 127 } 128 129 func (e *sampleValidationError) Error() string { 130 return fmt.Sprintf(e.message, e.timestamp, e.metricName) 131 } 132 133 func newSampleTimestampTooOldError(metricName string, timestamp int64) ValidationError { 134 return &sampleValidationError{ 135 message: "timestamp too old: %d metric: %.200q", 136 metricName: metricName, 137 timestamp: timestamp, 138 } 139 } 140 141 func newSampleTimestampTooNewError(metricName string, timestamp int64) ValidationError { 142 return &sampleValidationError{ 143 message: "timestamp too new: %d metric: %.200q", 144 metricName: metricName, 145 timestamp: timestamp, 146 } 147 } 148 149 // exemplarValidationError is a ValidationError implementation suitable for exemplar validation errors. 150 type exemplarValidationError struct { 151 message string 152 seriesLabels []cortexpb.LabelAdapter 153 exemplarLabels []cortexpb.LabelAdapter 154 timestamp int64 155 } 156 157 func (e *exemplarValidationError) Error() string { 158 return fmt.Sprintf(e.message, e.timestamp, cortexpb.FromLabelAdaptersToLabels(e.seriesLabels).String(), cortexpb.FromLabelAdaptersToLabels(e.exemplarLabels).String()) 159 } 160 161 func newExemplarEmtpyLabelsError(seriesLabels []cortexpb.LabelAdapter, exemplarLabels []cortexpb.LabelAdapter, timestamp int64) ValidationError { 162 return &exemplarValidationError{ 163 message: "exemplar missing labels, timestamp: %d series: %s labels: %s", 164 seriesLabels: seriesLabels, 165 exemplarLabels: exemplarLabels, 166 timestamp: timestamp, 167 } 168 } 169 170 func newExemplarMissingTimestampError(seriesLabels []cortexpb.LabelAdapter, exemplarLabels []cortexpb.LabelAdapter, timestamp int64) ValidationError { 171 return &exemplarValidationError{ 172 message: "exemplar missing timestamp, timestamp: %d series: %s labels: %s", 173 seriesLabels: seriesLabels, 174 exemplarLabels: exemplarLabels, 175 timestamp: timestamp, 176 } 177 } 178 179 var labelLenMsg = "exemplar combined labelset exceeds " + strconv.Itoa(ExemplarMaxLabelSetLength) + " characters, timestamp: %d series: %s labels: %s" 180 181 func newExemplarLabelLengthError(seriesLabels []cortexpb.LabelAdapter, exemplarLabels []cortexpb.LabelAdapter, timestamp int64) ValidationError { 182 return &exemplarValidationError{ 183 message: labelLenMsg, 184 seriesLabels: seriesLabels, 185 exemplarLabels: exemplarLabels, 186 timestamp: timestamp, 187 } 188 } 189 190 // formatLabelSet formats label adapters as a metric name with labels, while preserving 191 // label order, and keeping duplicates. If there are multiple "__name__" labels, only 192 // first one is used as metric name, other ones will be included as regular labels. 193 func formatLabelSet(ls []cortexpb.LabelAdapter) string { 194 metricName, hasMetricName := "", false 195 196 labelStrings := make([]string, 0, len(ls)) 197 for _, l := range ls { 198 if l.Name == model.MetricNameLabel && !hasMetricName && l.Value != "" { 199 metricName = l.Value 200 hasMetricName = true 201 } else { 202 labelStrings = append(labelStrings, fmt.Sprintf("%s=%q", l.Name, l.Value)) 203 } 204 } 205 206 if len(labelStrings) == 0 { 207 if hasMetricName { 208 return metricName 209 } 210 return "{}" 211 } 212 213 return fmt.Sprintf("%s{%s}", metricName, strings.Join(labelStrings, ", ")) 214 }