Skip to content

Commit

Permalink
Optimize TextFormatter
Browse files Browse the repository at this point in the history
  • Loading branch information
phnx47 committed Jan 4, 2019
1 parent 54ffe38 commit bce89e9
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 37 deletions.
1 change: 1 addition & 0 deletions src/Prometheus.Client/Contracts/CMetric.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public class CMetric
public CCounter CCounter { get; set; }

public CSummary CSummary { get; set; }


public CUntyped CUntyped { get; set; }

Expand Down
118 changes: 81 additions & 37 deletions src/Prometheus.Client/TextFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,76 +13,120 @@ public static class TextFormatter

public static void Format(Stream destination, CMetricFamily[] metrics)
{
var metricFamilys = metrics.ToArray();
using (var streamWriter = new StreamWriter(destination, _encoding, 1024, true))
{
streamWriter.NewLine = "\n";
foreach (var metricFamily in metricFamilys)
foreach (var metricFamily in metrics)
WriteFamily(streamWriter, metricFamily);
}
}

private static void WriteFamily(StreamWriter streamWriter, CMetricFamily cMetricFamily)
private static void WriteFamily(StreamWriter streamWriter, CMetricFamily metricFamily)
{
streamWriter.WriteLine("# HELP {0} {1}", cMetricFamily.Name, cMetricFamily.Help);
streamWriter.WriteLine("# TYPE {0} {1}", cMetricFamily.Name, cMetricFamily.Type.ToString().ToLower());
foreach (var metric in cMetricFamily.Metrics)
WriteMetric(streamWriter, cMetricFamily, metric);
// # HELP
streamWriter.Write("# HELP ");
streamWriter.Write(metricFamily.Name);
streamWriter.Write(" ");
streamWriter.WriteLine(metricFamily.Help);

// # TYPE
streamWriter.Write("# TYPE ");
streamWriter.Write(metricFamily.Name);
streamWriter.Write(" ");
streamWriter.WriteLine(metricFamily.Type.ToString().ToLowerInvariant());

foreach (var metric in metricFamily.Metrics)
WriteMetric(streamWriter, metricFamily, metric);
}

private static void WriteMetric(StreamWriter streamWriter, CMetricFamily family, CMetric cMetric)
private static void WriteMetric(StreamWriter streamWriter, CMetricFamily family, CMetric metric)
{
var familyName = family.Name;
if (cMetric.CGauge != null)

if (metric.CGauge != null)
{
streamWriter.WriteLine(SimpleValue(familyName, cMetric.CGauge.Value, cMetric.Labels));
WriteMetricValue(streamWriter, familyName, null, metric.CGauge.Value, metric.Labels);
}
else if (cMetric.CCounter != null)
else if (metric.CCounter != null)
{
streamWriter.WriteLine(SimpleValue(familyName, cMetric.CCounter.Value, cMetric.Labels));
WriteMetricValue(streamWriter, familyName, null, metric.CCounter.Value, metric.Labels);
}
else if (cMetric.CSummary != null)
else if (metric.CSummary != null)
{
streamWriter.WriteLine(SimpleValue(familyName, cMetric.CSummary.SampleSum, cMetric.Labels, "_sum"));
streamWriter.WriteLine(SimpleValue(familyName, cMetric.CSummary.SampleCount, cMetric.Labels, "_count"));
WriteMetricValue(streamWriter, familyName, "_sum", metric.CSummary.SampleSum, metric.Labels);
WriteMetricValue(streamWriter, familyName, "_count", metric.CSummary.SampleCount, metric.Labels);

foreach (var quantileValuePair in cMetric.CSummary.Quantiles)
foreach (var quantileValuePair in metric.CSummary.Quantiles)
{
var quantile = double.IsPositiveInfinity(quantileValuePair.Quantile)
? "+Inf"
: quantileValuePair.Quantile.ToString(CultureInfo.InvariantCulture);
streamWriter.WriteLine(SimpleValue(familyName, quantileValuePair.Value,
cMetric.Labels.Concat(new[] { new CLabelPair { Name = "quantile", Value = quantile } })));
var quantile = double.IsPositiveInfinity(quantileValuePair.Quantile) ? "+Inf" : quantileValuePair.Quantile.ToString(CultureInfo.InvariantCulture);

var quantileLabels = metric.Labels.Concat(new[]
{
new CLabelPair { Name = "quantile", Value = quantile }
}).ToArray();

WriteMetricValue(streamWriter, familyName, null, quantileValuePair.Value, quantileLabels);
}
}
else if (cMetric.CHistogram != null)
else if (metric.CHistogram != null)
{
streamWriter.WriteLine(SimpleValue(familyName, cMetric.CHistogram.SampleSum, cMetric.Labels, "_sum"));
streamWriter.WriteLine(SimpleValue(familyName, cMetric.CHistogram.SampleCount, cMetric.Labels, "_count"));
foreach (var bucket in cMetric.CHistogram.Buckets)
WriteMetricValue(streamWriter, familyName, "_sum", metric.CHistogram.SampleSum, metric.Labels);
WriteMetricValue(streamWriter, familyName, "_count", metric.CHistogram.SampleCount, metric.Labels);

foreach (var bucket in metric.CHistogram.Buckets)
{
var value = double.IsPositiveInfinity(bucket.UpperBound) ? "+Inf" : bucket.UpperBound.ToString(CultureInfo.InvariantCulture);
streamWriter.WriteLine(SimpleValue(familyName, bucket.CumulativeCount,
cMetric.Labels.Concat(new[] { new CLabelPair { Name = "le", Value = value } }), "_bucket"));

var bucketLabels = metric.Labels.Concat(new[]
{
new CLabelPair { Name = "le", Value = value }
}).ToArray();

WriteMetricValue(streamWriter, familyName, "_bucket", bucket.CumulativeCount, bucketLabels);
}
}
}

private static string WithLabels(string familyName, IEnumerable<CLabelPair> labels)
private static void WriteMetricValue(StreamWriter writer, string familyName, string postfix, double value, CLabelPair[] labels)
{
var labelPairs = labels as CLabelPair[] ?? labels.ToArray();
return labelPairs.Length == 0 ? familyName : $"{familyName}{{{string.Join(",", labelPairs.Select(l => $"{l.Name}=\"{EscapeValue(l.Value)}\""))}}}";
}
writer.Write(familyName);

private static string EscapeValue(string val)
{
return val.Replace("\\", @"\\").Replace("\n", @"\n").Replace("\"", @"\""");
if (postfix != null)
writer.Write(postfix);

if (labels?.Any() == true)
{
writer.Write('{');

bool firstLabel = true;
foreach (var label in labels)
{
if (!firstLabel)
writer.Write(',');

firstLabel = false;

writer.Write(label.Name);
writer.Write("=\"");
writer.Write(EscapeValue(label.Value));

writer.Write('"');
}

writer.Write('}');
}

writer.Write(' ');
writer.WriteLine(value.ToString(CultureInfo.InvariantCulture));
}

private static string SimpleValue(string family, double value, IEnumerable<CLabelPair> labels, string namePostfix = null)

private static string EscapeValue(string val)
{
return $"{WithLabels(family + (namePostfix ?? ""), labels)} {value.ToString(CultureInfo.InvariantCulture)}";
return val
.Replace("\\", @"\\")
.Replace("\n", @"\n")
.Replace("\"", @"\""");
}
}
}

0 comments on commit bce89e9

Please sign in to comment.