@@ -70,19 +70,34 @@ func ResponseFormat(h http.Header) Format {
70
70
return FmtUnknown
71
71
}
72
72
73
- // NewDecoder returns a new decoder based on the given input format.
74
- // If the input format does not imply otherwise, a text format decoder is returned.
73
+ // NewDecoder returns a new decoder based on the given input format. Metric
74
+ // names are validated based on the provided Format -- if the format requires
75
+ // escaping, raditional Prometheues validity checking is used. Otherwise, names
76
+ // are checked for UTF-8 validity. Supported formats include delimited protobuf
77
+ // and Prometheus text format. For historical reasons, this decoder fallbacks
78
+ // to classic text decoding for any other format. This decoder does not fully
79
+ // support OpenMetrics although it may often succeed due to the similarities
80
+ // between the formats. This decoder may not support the latest features of
81
+ // Prometheus text format and is not intended for high-performance applications.
82
+ // See: https://github.com/prometheus/common/issues/812
75
83
func NewDecoder (r io.Reader , format Format ) Decoder {
84
+ scheme := model .LegacyValidation
85
+ if format .ToEscapingScheme () == model .NoEscaping {
86
+ scheme = model .UTF8Validation
87
+ }
76
88
switch format .FormatType () {
77
89
case TypeProtoDelim :
78
- return & protoDecoder {r : bufio .NewReader (r )}
90
+ return & protoDecoder {r : bufio .NewReader (r ), s : scheme }
91
+ case TypeProtoText , TypeProtoCompact :
92
+ return & errDecoder {err : fmt .Errorf ("format %s not supported for decoding" , format )}
79
93
}
80
- return & textDecoder {r : r }
94
+ return & textDecoder {r : r , s : scheme }
81
95
}
82
96
83
97
// protoDecoder implements the Decoder interface for protocol buffers.
84
98
type protoDecoder struct {
85
99
r protodelim.Reader
100
+ s model.ValidationScheme
86
101
}
87
102
88
103
// Decode implements the Decoder interface.
@@ -93,8 +108,7 @@ func (d *protoDecoder) Decode(v *dto.MetricFamily) error {
93
108
if err := opts .UnmarshalFrom (d .r , v ); err != nil {
94
109
return err
95
110
}
96
- //nolint:staticcheck // model.IsValidMetricName is deprecated.
97
- if ! model .IsValidMetricName (model .LabelValue (v .GetName ())) {
111
+ if ! d .s .IsValidMetricName (v .GetName ()) {
98
112
return fmt .Errorf ("invalid metric name %q" , v .GetName ())
99
113
}
100
114
for _ , m := range v .GetMetric () {
@@ -108,27 +122,36 @@ func (d *protoDecoder) Decode(v *dto.MetricFamily) error {
108
122
if ! model .LabelValue (l .GetValue ()).IsValid () {
109
123
return fmt .Errorf ("invalid label value %q" , l .GetValue ())
110
124
}
111
- //nolint:staticcheck // model.LabelName.IsValid is deprecated.
112
- if ! model .LabelName (l .GetName ()).IsValid () {
125
+ if ! d .s .IsValidLabelName (l .GetName ()) {
113
126
return fmt .Errorf ("invalid label name %q" , l .GetName ())
114
127
}
115
128
}
116
129
}
117
130
return nil
118
131
}
119
132
133
+ // errDecoder is an error-state decoder that always returns the same error.
134
+ type errDecoder struct {
135
+ err error
136
+ }
137
+
138
+ func (d * errDecoder ) Decode (v * dto.MetricFamily ) error {
139
+ return d .err
140
+ }
141
+
120
142
// textDecoder implements the Decoder interface for the text protocol.
121
143
type textDecoder struct {
122
144
r io.Reader
123
145
fams map [string ]* dto.MetricFamily
146
+ s model.ValidationScheme
124
147
err error
125
148
}
126
149
127
150
// Decode implements the Decoder interface.
128
151
func (d * textDecoder ) Decode (v * dto.MetricFamily ) error {
129
152
if d .err == nil {
130
153
// Read all metrics in one shot.
131
- var p TextParser
154
+ p := TextParser { scheme : d . s }
132
155
d .fams , d .err = p .TextToMetricFamilies (d .r )
133
156
// If we don't get an error, store io.EOF for the end.
134
157
if d .err == nil {
0 commit comments