@@ -133,7 +133,7 @@ var ErrMetricNameParsing = errors.New("parsing metric name failed")
133133// of "key:value" strings. On failure, it returns an error containing the `ErrMetricNameParsing` in its chain.
134134func ParseMetricName (name string ) (string , []string , error ) {
135135 openingTokenPos := strings .IndexByte (name , '{' )
136- closingTokenPos := strings .IndexByte (name , '}' )
136+ closingTokenPos := strings .LastIndexByte (name , '}' )
137137 containsOpeningToken := openingTokenPos != - 1
138138 containsClosingToken := closingTokenPos != - 1
139139
@@ -147,37 +147,44 @@ func ParseMetricName(name string) (string, []string, error) {
147147 // its counterpart, the expression is malformed.
148148 if (containsOpeningToken && ! containsClosingToken ) ||
149149 (! containsOpeningToken && containsClosingToken ) {
150- return "" , nil , fmt .Errorf ("%w; reason: unmatched opening/close curly brace" , ErrMetricNameParsing )
150+ return "" , nil , fmt .Errorf (
151+ "%w, metric %q has unmatched opening/close curly brace" ,
152+ ErrMetricNameParsing , name ,
153+ )
151154 }
152155
156+ // If the closing brace token appears before the opening one,
157+ // the expression is malformed
153158 if closingTokenPos < openingTokenPos {
154- return "" , nil , fmt .Errorf ("%w; reason: closing curly brace appears before opening one" , ErrMetricNameParsing )
159+ return "" , nil , fmt .Errorf ("%w, metric %q closing curly brace appears before opening one" , ErrMetricNameParsing , name )
155160 }
156161
157- parserFn := func (c rune ) bool {
158- return c == '{' || c == '}'
162+ // If the last character is not a closing brace token,
163+ // the expression is malformed.
164+ if closingTokenPos != (len (name ) - 1 ) {
165+ err := fmt .Errorf (
166+ "%w, metric %q lacks a closing curly brace in its last position" ,
167+ ErrMetricNameParsing ,
168+ name ,
169+ )
170+ return "" , nil , err
159171 }
160172
161- // Split the metric_name{tag_key:tag_value,...} expression
162- // into two "metric_name" and "tag_key:tag_value,..." strings.
163- parts := strings .FieldsFunc (name , parserFn )
164- if len (parts ) == 0 || len (parts ) > 2 {
165- return "" , nil , ErrMetricNameParsing
166- }
167-
168- // Split the tag key values
169- tags := strings .Split (parts [1 ], "," )
173+ // We already know the position of the opening and closing curly brace
174+ // tokens. Thus, we extract the string in between them, and split its
175+ // content to obtain the tags key values.
176+ tags := strings .Split (name [openingTokenPos + 1 :closingTokenPos ], "," )
170177
171- // For each tag definition, ensure
178+ // For each tag definition, ensure it is correctly formed
172179 for i , t := range tags {
173180 keyValue := strings .SplitN (t , ":" , 2 )
174181
175182 if len (keyValue ) != 2 || keyValue [1 ] == "" {
176- return "" , nil , fmt .Errorf ("%w; reason: malformed tag expression %q " , ErrMetricNameParsing , t )
183+ return "" , nil , fmt .Errorf ("%w, metric %q tag expression is malformed " , ErrMetricNameParsing , t )
177184 }
178185
179186 tags [i ] = strings .TrimSpace (t )
180187 }
181188
182- return parts [ 0 ], tags , nil
189+ return name [ 0 : openingTokenPos ], tags , nil
183190}
0 commit comments