Copilot commented on code in PR #1153:
URL:
https://github.com/apache/skywalking-banyandb/pull/1153#discussion_r3353409941
##########
fodc/proxy/internal/api/server.go:
##########
@@ -354,31 +409,71 @@ func (s *Server) formatPrometheusText(aggregatedMetrics
[]*metrics.AggregatedMet
regularNames = append(regularNames, name)
}
sort.Strings(regularNames)
-
for _, name := range regularNames {
- group := regularMetrics[name]
- if group.description != "" {
- builder.WriteString(fmt.Sprintf("# HELP %s %s\n",
group.name, group.description))
+ grp := regularMetrics[name]
+ if grp.description != "" {
+ builder.WriteString(fmt.Sprintf("# HELP %s %s\n",
grp.name, grp.description))
+ }
+ builder.WriteString(fmt.Sprintf("# TYPE %s gauge\n", grp.name))
+ for _, m := range grp.metrics {
+ builder.WriteString(formatMetricLine(m))
}
- builder.WriteString(fmt.Sprintf("# TYPE %s gauge\n",
group.name))
+ }
+}
- for _, metric := range group.metrics {
- labelParts := make([]string, 0, len(metric.Labels))
- for key, value := range metric.Labels {
- labelParts = append(labelParts,
fmt.Sprintf(`%s="%s"`, key, value))
+// matchTypedFamily returns the typed family an untyped series belongs to, or
nil if none.
+// It checks the exact name first (counter/gauge/untyped series and bare
summary quantile
+// series), then the histogram/summary component base after trimming a trailing
+// _bucket/_sum/_count suffix. Used to fold pre-upgrade (untyped) samples into
the
+// authoritative typed family so the proxy never emits two TYPE lines for one
name.
+func matchTypedFamily(typedFamilies map[string]*metricGroup, name string)
*metricGroup {
+ if grp, ok := typedFamilies[name]; ok {
+ return grp
+ }
+ for _, suffix := range []string{"_bucket", "_sum", "_count"} {
+ if strings.HasSuffix(name, suffix) {
+ base := strings.TrimSuffix(name, suffix)
+ if base != "" {
+ if grp, ok := typedFamilies[base]; ok {
+ return grp
+ }
}
- sort.Strings(labelParts)
+ break
+ }
+ }
+ return nil
+}
- labelStr := ""
- if len(labelParts) > 0 {
- labelStr = "{" + strings.Join(labelParts, ",")
+ "}"
+// typedFamilyBase returns the Prometheus family base name for a typed series.
+// For histogram/summary component series the trailing _bucket/_sum/_count is
stripped.
+// For all other types (counter, gauge, untyped) the name is used as-is.
+func typedFamilyBase(name, metricType string) string {
+ switch metricType {
+ case "histogram", "summary":
+ for _, suffix := range []string{"_bucket", "_sum", "_count"} {
+ if strings.HasSuffix(name, suffix) {
+ base := strings.TrimSuffix(name, suffix)
+ if base != "" {
+ return base
+ }
}
-
- builder.WriteString(fmt.Sprintf("%s%s %s\n",
group.name, labelStr, formatFloat(metric.Value)))
}
}
+ return name
+}
- return builder.String()
+// formatMetricLine renders a single metric sample as a Prometheus text line.
+func formatMetricLine(m *metrics.AggregatedMetric) string {
+ labelParts := make([]string, 0, len(m.Labels))
+ for k, v := range m.Labels {
+ labelParts = append(labelParts, fmt.Sprintf(`%s="%s"`, k, v))
+ }
+ sort.Strings(labelParts)
+ labelStr := ""
+ if len(labelParts) > 0 {
+ labelStr = "{" + strings.Join(labelParts, ",") + "}"
+ }
+ return fmt.Sprintf("%s%s %s\n", m.Name, labelStr, formatFloat(m.Value))
}
Review Comment:
Prometheus text exposition requires label values to be escaped (\, ", and
newlines). formatMetricLine currently interpolates raw label values into
`key="value"`, which can produce invalid `/metrics` output if any label
contains special characters, causing Prometheus scrape failures.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]