diff --git a/expfmt/openmetrics_create.go b/expfmt/openmetrics_create.go index bdc2e3b9..0c914718 100644 --- a/expfmt/openmetrics_create.go +++ b/expfmt/openmetrics_create.go @@ -90,11 +90,6 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int if metricType == dto.MetricType_COUNTER && strings.HasSuffix(shortName, "_total") { shortName = name[:len(name)-6] } - // If the name does not satisfy the legacy validity check, we must quote it. - quotedName := shortName - if !model.IsValidLegacyMetricName(model.LabelValue(quotedName)) { - quotedName = strconv.Quote(quotedName) - } // Comments, first HELP, then TYPE. if in.Help != nil { @@ -103,7 +98,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int if err != nil { return } - n, err = w.WriteString(quotedName) + n, err = writeName(w, shortName) written += n if err != nil { return @@ -129,7 +124,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int if err != nil { return } - n, err = w.WriteString(quotedName) + n, err = writeName(w, shortName) written += n if err != nil { return @@ -382,10 +377,10 @@ func writeOpenMetricsNameAndLabelPairs( if err != nil { return written, err } - name = strconv.Quote(name) separator = ',' } - n, err := w.WriteString(name) + + n, err := writeName(w, name) written += n if err != nil { return written, err @@ -409,11 +404,7 @@ func writeOpenMetricsNameAndLabelPairs( if err != nil { return written, err } - labelName := lp.GetName() - if !model.IsValidLegacyMetricName(model.LabelValue(labelName)) { - labelName = strconv.Quote(labelName) - } - n, err := w.WriteString(labelName) + n, err := writeName(w, lp.GetName()) written += n if err != nil { return written, err diff --git a/expfmt/text_create.go b/expfmt/text_create.go index 0c21f205..2078654d 100644 --- a/expfmt/text_create.go +++ b/expfmt/text_create.go @@ -73,11 +73,6 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err e return 0, fmt.Errorf("MetricFamily has no name: %s", in) } - // If the name does not satisfy the legacy validity check, we must quote it. - quotedName := name - if !model.IsValidLegacyMetricName(model.LabelValue(quotedName)) { - quotedName = strconv.Quote(quotedName) - } // Try the interface upgrade. If it doesn't work, we'll use a // bufio.Writer from the sync.Pool. w, ok := out.(enhancedWriter) @@ -103,7 +98,7 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err e if err != nil { return } - n, err = w.WriteString(quotedName) + n, err = writeName(w, name) written += n if err != nil { return @@ -129,7 +124,7 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err e if err != nil { return } - n, err = w.WriteString(quotedName) + n, err = writeName(w, name) written += n if err != nil { return @@ -344,7 +339,7 @@ func writeNameAndLabelPairs( if name != "" { // If the name does not pass the legacy validity check, we must put the - // metric name inside the braces. Note, it will already have been + // metric name inside the braces. if !model.IsValidLegacyMetricName(model.LabelValue(name)) { metricInsideBraces = true err := w.WriteByte(separator) @@ -352,10 +347,9 @@ func writeNameAndLabelPairs( if err != nil { return written, err } - name = strconv.Quote(name) separator = ',' } - n, err := w.WriteString(name) + n, err := writeName(w, name) written += n if err != nil { return written, err @@ -379,11 +373,7 @@ func writeNameAndLabelPairs( if err != nil { return written, err } - labelName := lp.GetName() - if !model.IsValidLegacyMetricName(model.LabelValue(labelName)) { - labelName = strconv.Quote(labelName) - } - n, err := w.WriteString(labelName) + n, err := writeName(w, lp.GetName()) written += n if err != nil { return written, err @@ -490,3 +480,27 @@ func writeInt(w enhancedWriter, i int64) (int, error) { numBufPool.Put(bp) return written, err } + +// writeName writes a string as-is if it complies with the legacy naming +// scheme, or escapes it in double quotes if not. +func writeName(w enhancedWriter, name string) (int, error) { + if !model.IsValidLegacyMetricName(model.LabelValue(name)) { + var written int + var err error + err = w.WriteByte('"') + written++ + if err != nil { + return written, err + } + var n int + n, err = writeEscapedString(w, name, true) + written += n + if err != nil { + return written, err + } + err = w.WriteByte('"') + written++ + return written, err + } + return w.WriteString(name) +} \ No newline at end of file diff --git a/model/metric.go b/model/metric.go index a834f4b3..d92631b5 100644 --- a/model/metric.go +++ b/model/metric.go @@ -116,8 +116,7 @@ func IsValidMetricName(n LabelValue) bool { } // IsValidLegacyMetricName is similar to IsValidMetricName but always uses the -// legacy validation scheme regardless of the value of NameValidationScheme. It -// returns true iff name matches the pattern of MetricNameRE for legacy names. +// legacy validation scheme regardless of the value of NameValidationScheme. // This function, however, does not use MetricNameRE for the check but a much // faster hardcoded implementation. func IsValidLegacyMetricName(n LabelValue) bool {