module metrics import strings import io pub struct PrometheusExporter { mut: prefix string collector &MetricsCollector = unsafe { nil } } pub fn new_prometheus_exporter() PrometheusExporter { return PrometheusExporter{} } pub fn (mut e PrometheusExporter) load(prefix string, collector &MetricsCollector) { unsafe { e.collector = collector } e.prefix = prefix } [inline] fn join_two_array(arr [2]string) string { return '${arr[0]}="${arr[1]}"' } pub fn (e &PrometheusExporter) serialize_metric(metric Metric) string { if metric.labels.len == 0 { return '${e.prefix}${metric.name}' } return '${e.prefix}${metric.name}{${metric.labels.map(join_two_array(it)).join(',')}}' } pub fn (mut e PrometheusExporter) export_to_string() !string { mut builder := strings.new_builder(64) e.export_to_writer(mut builder)! return builder.str() } pub fn (mut e PrometheusExporter) export_to_writer(mut writer io.Writer) ! { for counter in e.collector.counters() { val := e.collector.counter_get(counter) or { return error("This can't happen.") } line := '${e.serialize_metric(counter)} ${val}\n' writer.write(line.bytes())! } for gauge in e.collector.gauges() { val := e.collector.gauge_get(gauge) or { return error("This can't happen.") } line := '${e.serialize_metric(gauge)} ${val}\n' writer.write(line.bytes())! } for hist in e.collector.histograms() { hist_data := e.collector.histogram_get(hist) or { return error("This can't happen.") } mut m := Metric{ ...hist name: '${hist.name}_count' } writer.write('${e.serialize_metric(m)} ${hist_data.total_count}\n'.bytes())! m = Metric{ ...hist name: '${hist.name}_sum' } writer.write('${e.serialize_metric(m)} ${hist_data.sum}\n'.bytes())! mut le_labels := [][2]string{} le_labels.prepend(hist.labels) le_labels << ['le', '']! for j, bucket in hist_data.buckets { le_labels[le_labels.len - 1][1] = bucket.str() m = Metric{ name: '${hist.name}_bucket' labels: le_labels } writer.write('${e.serialize_metric(m)} ${hist_data.bucket_counts[j]}\n'.bytes())! } // Always output the +Inf bucket le_labels[le_labels.len - 1][1] = '+Inf' if hist_data.buckets.len > 0 { m = Metric{ name: '${hist.name}_bucket' labels: le_labels } writer.write('${e.serialize_metric(m)} ${hist_data.total_count}\n'.bytes())! } } }