@@ -23,6 +23,7 @@ import (
2323
2424 dto "github.com/prometheus/client_model/go"
2525 "google.golang.org/protobuf/encoding/protodelim"
26+ "google.golang.org/protobuf/encoding/prototext"
2627
2728 "github.com/prometheus/common/model"
2829)
@@ -70,19 +71,34 @@ func ResponseFormat(h http.Header) Format {
7071 return FmtUnknown
7172}
7273
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.
74+ // NewDecoder returns a new decoder based on the given input format. Supported
75+ // formats include delimited protobuf, text protos, and Prometheus text format.
76+ // This decoder does not fully support OpenMetrics although it may often succeed
77+ // due to the similarities between the formats. This decoder may not support the
78+ // latest features of Prometheus text format and is not intended for
79+ // high-performance applications. The parsers in Prometheus
80+ // (https://github.com/prometheus/prometheus/blob/main/model/textparse/promparse.go
81+ // and
82+ // https://github.com/prometheus/prometheus/blob/main/model/textparse/openmetricsparse.go)
83+ // are more regularly maintained.
7584func NewDecoder (r io.Reader , format Format ) Decoder {
85+ scheme := model .LegacyValidation
86+ if format .ToEscapingScheme () == model .NoEscaping {
87+ scheme = model .UTF8Validation
88+ }
7689 switch format .FormatType () {
7790 case TypeProtoDelim :
78- return & protoDecoder {r : bufio .NewReader (r )}
91+ return & protoDecoder {r : bufio .NewReader (r ), s : scheme }
92+ case TypeProtoText , TypeProtoCompact :
93+ return & prototextDecoder {r : r , s : scheme }
7994 }
80- return & textDecoder {r : r }
95+ return & textDecoder {r : r , s : scheme }
8196}
8297
8398// protoDecoder implements the Decoder interface for protocol buffers.
8499type protoDecoder struct {
85100 r protodelim.Reader
101+ s model.ValidationScheme
86102}
87103
88104// Decode implements the Decoder interface.
@@ -93,8 +109,46 @@ func (d *protoDecoder) Decode(v *dto.MetricFamily) error {
93109 if err := opts .UnmarshalFrom (d .r , v ); err != nil {
94110 return err
95111 }
96- //nolint:staticcheck // model.IsValidMetricName is deprecated.
97- if ! model .IsValidMetricName (model .LabelValue (v .GetName ())) {
112+ if ! d .s .IsValidMetricName (v .GetName ()) {
113+ return fmt .Errorf ("invalid metric name %q" , v .GetName ())
114+ }
115+ for _ , m := range v .GetMetric () {
116+ if m == nil {
117+ continue
118+ }
119+ for _ , l := range m .GetLabel () {
120+ if l == nil {
121+ continue
122+ }
123+ if ! model .LabelValue (l .GetValue ()).IsValid () {
124+ return fmt .Errorf ("invalid label value %q" , l .GetValue ())
125+ }
126+ if ! d .s .IsValidLabelName (l .GetName ()) {
127+ return fmt .Errorf ("invalid label name %q" , l .GetName ())
128+ }
129+ }
130+ }
131+ return nil
132+ }
133+
134+ // prototextDecoder implements the Decoder interface for protocol buffers that
135+ // are encoded in text format.
136+ type prototextDecoder struct {
137+ r io.Reader
138+ s model.ValidationScheme
139+ }
140+
141+ // Decode implements the Decoder interface.
142+ func (d * prototextDecoder ) Decode (v * dto.MetricFamily ) error {
143+ opts := prototext.UnmarshalOptions {}
144+ b , err := io .ReadAll (d .r )
145+ if err != nil {
146+ return err
147+ }
148+ if err := opts .Unmarshal (b , v ); err != nil {
149+ return err
150+ }
151+ if ! d .s .IsValidMetricName (v .GetName ()) {
98152 return fmt .Errorf ("invalid metric name %q" , v .GetName ())
99153 }
100154 for _ , m := range v .GetMetric () {
@@ -108,8 +162,7 @@ func (d *protoDecoder) Decode(v *dto.MetricFamily) error {
108162 if ! model .LabelValue (l .GetValue ()).IsValid () {
109163 return fmt .Errorf ("invalid label value %q" , l .GetValue ())
110164 }
111- //nolint:staticcheck // model.LabelName.IsValid is deprecated.
112- if ! model .LabelName (l .GetName ()).IsValid () {
165+ if ! d .s .IsValidLabelName (l .GetName ()) {
113166 return fmt .Errorf ("invalid label name %q" , l .GetName ())
114167 }
115168 }
@@ -121,14 +174,15 @@ func (d *protoDecoder) Decode(v *dto.MetricFamily) error {
121174type textDecoder struct {
122175 r io.Reader
123176 fams map [string ]* dto.MetricFamily
177+ s model.ValidationScheme
124178 err error
125179}
126180
127181// Decode implements the Decoder interface.
128182func (d * textDecoder ) Decode (v * dto.MetricFamily ) error {
129183 if d .err == nil {
130184 // Read all metrics in one shot.
131- var p TextParser
185+ p := TextParser { scheme : d . s }
132186 d .fams , d .err = p .TextToMetricFamilies (d .r )
133187 // If we don't get an error, store io.EOF for the end.
134188 if d .err == nil {
0 commit comments