package monitoring import ( "context" "fmt" "strings" ) // PrometheusExporter exports metrics in Prometheus format type PrometheusExporter struct { Collectors []Collector } func NewPrometheusExporter(collectors ...Collector) *PrometheusExporter { return &PrometheusExporter{Collectors: collectors} } // Export collects all metrics and formats them as Prometheus text format func (e *PrometheusExporter) Export(ctx context.Context) string { var builder strings.Builder allErrors := []string{} for _, collector := range e.Collectors { collection := collector.Collect(ctx) allErrors = append(allErrors, collection.Errors...) for _, metric := range collection.Metrics { // Format: metric_name{label1="value1",label2="value2"} value builder.WriteString(metric.Name) if len(metric.Labels) > 0 { builder.WriteString("{") first := true for k, v := range metric.Labels { if !first { builder.WriteString(",") } builder.WriteString(fmt.Sprintf(`%s="%s"`, k, escapeLabelValue(v))) first = false } builder.WriteString("}") } builder.WriteString(fmt.Sprintf(" %v\n", metric.Value)) } } // Add error metrics if any if len(allErrors) > 0 { builder.WriteString(fmt.Sprintf("monitoring_collector_errors_total %d\n", len(allErrors))) } return builder.String() } func escapeLabelValue(v string) string { v = strings.ReplaceAll(v, "\\", "\\\\") v = strings.ReplaceAll(v, "\"", "\\\"") v = strings.ReplaceAll(v, "\n", "\\n") return v }