public void Test(string cultureInfo) { if (!string.IsNullOrEmpty(cultureInfo)) { Thread.CurrentThread.CurrentCulture = new CultureInfo(cultureInfo); } using var stream = new MemoryStream(); using var writer = new StreamWriter(stream); var builder = new PrometheusMetricBuilder(); builder.WithName("test-builder"); builder.WithDescription("test-description"); builder.WithType("test-type"); var metricValueBuilder = builder.AddValue(); metricValueBuilder = metricValueBuilder.WithValue(10.0123); metricValueBuilder.WithLabel("test-double", "double"); builder.Write(writer); writer.Flush(); // assert string actual = Encoding.UTF8.GetString(stream.ToArray()); string[] lines = actual.Split('\n'); Assert.Equal("# HELP test_buildertest-description", lines[0]); Assert.Equal("# TYPE test_builder test-type", lines[1]); Assert.StartsWith("test_builder{test_double=\"double\"} 10.01", lines[2]); }
private void WorkerThread() { this.httpListener.Start(); try { while (!this.tokenSource.IsCancellationRequested) { var ctxTask = this.httpListener.GetContextAsync(); ctxTask.Wait(this.tokenSource.Token); var ctx = ctxTask.Result; ctx.Response.StatusCode = 200; ctx.Response.ContentType = PrometheusMetricBuilder.ContentType; using (var output = ctx.Response.OutputStream) { using (var writer = new StreamWriter(output)) { foreach (var metric in this.exporter.Metrics) { var labels = metric.Labels; var value = metric.Value; var builder = new PrometheusMetricBuilder() .WithName(metric.MetricName) .WithDescription(metric.MetricDescription); builder = builder.WithType("counter"); foreach (var label in labels) { var metricValueBuilder = builder.AddValue(); metricValueBuilder = metricValueBuilder.WithValue(value); metricValueBuilder.WithLabel(label.Key, label.Value); } builder.Write(writer); } } } } } catch (OperationCanceledException) { // this will happen when cancellation will be requested } catch (Exception) { // TODO: report error } finally { this.httpListener.Stop(); this.httpListener.Close(); } }
/// <summary> /// Serialize to Prometheus Format. /// </summary> /// <param name="exporter">Prometheus Exporter.</param> /// <param name="writer">StreamWriter to write to.</param> public static void WriteMetricsCollection(this PrometheusExporter exporter, StreamWriter writer) { foreach (var metric in exporter.GetAndClearMetrics()) { var builder = new PrometheusMetricBuilder() .WithName(metric.MetricName) .WithDescription(metric.MetricDescription); foreach (var metricData in metric.Data) { var labels = metricData.Labels; switch (metric.AggregationType) { case AggregationType.DoubleSum: { var sum = metricData as DoubleSumData; var sumValue = sum.Sum; WriteSum(writer, builder, labels, sumValue); break; } case AggregationType.LongSum: { var sum = metricData as Int64SumData; var sumValue = sum.Sum; WriteSum(writer, builder, labels, sumValue); break; } case AggregationType.DoubleSummary: { var summary = metricData as DoubleSummaryData; var count = summary.Count; var sum = summary.Sum; var min = summary.Min; var max = summary.Max; WriteSummary(writer, builder, labels, metric.MetricName, sum, count, min, max); break; } case AggregationType.Int64Summary: { var summary = metricData as Int64SummaryData; var count = summary.Count; var sum = summary.Sum; var min = summary.Min; var max = summary.Max; WriteSummary(writer, builder, labels, metric.MetricName, sum, count, min, max); break; } } } } }
private static void WriteSummary( StreamWriter writer, PrometheusMetricBuilder builder, IEnumerable <KeyValuePair <string, string> > labels, string metricName, double sum, long count, double min, double max) { builder = builder.WithType(PrometheusSummaryType); foreach (var label in labels) { /* For Summary we emit one row for Sum, Count, Min, Max. * Min,Max exportes as quantile 0 and 1. * In future, when OT implements more aggregation algorithms, * this section will need to be revisited. * Sample output: * MyMeasure_sum{dim1="value1"} 750 1587013352982 * MyMeasure_count{dim1="value1"} 5 1587013352982 * MyMeasure{dim1="value2",quantile="0"} 150 1587013352982 * MyMeasure{dim1="value2",quantile="1"} 150 1587013352982 */ var metricValueBuilder = builder.AddValue(); metricValueBuilder.WithName(metricName + PrometheusSummarySumPostFix); metricValueBuilder = metricValueBuilder.WithValue(sum); metricValueBuilder.WithLabel(label.Key, label.Value); metricValueBuilder = builder.AddValue(); metricValueBuilder.WithName(metricName + PrometheusSummaryCountPostFix); metricValueBuilder = metricValueBuilder.WithValue(count); metricValueBuilder.WithLabel(label.Key, label.Value); metricValueBuilder = builder.AddValue(); metricValueBuilder.WithName(metricName); metricValueBuilder = metricValueBuilder.WithValue(min); metricValueBuilder.WithLabel(label.Key, label.Value); metricValueBuilder.WithLabel(PrometheusSummaryQuantileLabelName, PrometheusSummaryQuantileLabelValueForMin); metricValueBuilder = builder.AddValue(); metricValueBuilder.WithName(metricName); metricValueBuilder = metricValueBuilder.WithValue(max); metricValueBuilder.WithLabel(label.Key, label.Value); metricValueBuilder.WithLabel(PrometheusSummaryQuantileLabelName, PrometheusSummaryQuantileLabelValueForMax); } builder.Write(writer); }
private static void WriteSum(StreamWriter writer, PrometheusMetricBuilder builder, IEnumerable <KeyValuePair <string, string> > labels, double doubleValue) { builder = builder.WithType(PrometheusCounterType); var metricValueBuilder = builder.AddValue(); metricValueBuilder = metricValueBuilder.WithValue(doubleValue); foreach (var label in labels) { metricValueBuilder.WithLabel(label.Key, label.Value); } builder.Write(writer); }
/// <summary> /// Serialize to Prometheus Format. /// </summary> /// <param name="exporter">Prometheus Exporter.</param> /// <param name="writer">StreamWriter to write to.</param> public static void WriteMetricsCollection(this PrometheusExporter exporter, StreamWriter writer) { foreach (var metricItem in exporter.Batch) { foreach (var metric in metricItem.Metrics) { var builder = new PrometheusMetricBuilder() .WithName(metric.Name) .WithDescription(metric.Description); // TODO: Use switch case for higher perf. if (metric.MetricType == MetricType.LongSum) { WriteSum(writer, builder, metric.Attributes, (metric as ISumMetricLong).LongSum); } else if (metric.MetricType == MetricType.DoubleSum) { WriteSum(writer, builder, metric.Attributes, (metric as ISumMetricDouble).DoubleSum); } else if (metric.MetricType == MetricType.DoubleGauge) { var gaugeMetric = metric as IGaugeMetric; var doubleValue = (double)gaugeMetric.LastValue.Value; WriteGauge(writer, builder, metric.Attributes, doubleValue); } else if (metric.MetricType == MetricType.LongGauge) { var gaugeMetric = metric as IGaugeMetric; var longValue = (long)gaugeMetric.LastValue.Value; // TODO: Prometheus only supports float/double WriteGauge(writer, builder, metric.Attributes, longValue); } else if (metric.MetricType == MetricType.Histogram) { var histogramMetric = metric as IHistogramMetric; WriteHistogram(writer, builder, metric.Attributes, metric.Name, histogramMetric.PopulationSum, histogramMetric.PopulationCount, histogramMetric.Buckets); } } } }
private static void WriteHistogram( StreamWriter writer, PrometheusMetricBuilder builder, IEnumerable <KeyValuePair <string, object> > labels, string metricName, double sum, long count, IEnumerable <HistogramBucket> buckets) { /* For Histogram we emit one row for Sum, Count and as * many rows as number of buckets. * myHistogram_sum{tag1="value1",tag2="value2"} 258330 1629860660991 * myHistogram_count{tag1="value1",tag2="value2"} 355 1629860660991 * myHistogram_bucket{tag1="value1",tag2="value2",le="0"} 0 1629860660991 * myHistogram_bucket{tag1="value1",tag2="value2",le="5"} 2 1629860660991 * myHistogram_bucket{tag1="value1",tag2="value2",le="10"} 4 1629860660991 * myHistogram_bucket{tag1="value1",tag2="value2",le="25"} 6 1629860660991 * myHistogram_bucket{tag1="value1",tag2="value2",le="50"} 12 1629860660991 * myHistogram_bucket{tag1="value1",tag2="value2",le="75"} 19 1629860660991 * myHistogram_bucket{tag1="value1",tag2="value2",le="100"} 26 1629860660991 * myHistogram_bucket{tag1="value1",tag2="value2",le="250"} 65 1629860660991 * myHistogram_bucket{tag1="value1",tag2="value2",le="500"} 128 1629860660991 * myHistogram_bucket{tag1="value1",tag2="value2",le="1000"} 241 1629860660991 * myHistogram_bucket{tag1="value1",tag2="value2",le="+Inf"} 355 1629860660991 */ builder = builder.WithType(PrometheusHistogramType); var metricValueBuilderSum = builder.AddValue(); metricValueBuilderSum.WithName(metricName + PrometheusHistogramSumPostFix); metricValueBuilderSum = metricValueBuilderSum.WithValue(sum); foreach (var label in labels) { metricValueBuilderSum.WithLabel(label.Key, label.Value.ToString()); } var metricValueBuilderCount = builder.AddValue(); metricValueBuilderCount.WithName(metricName + PrometheusHistogramCountPostFix); metricValueBuilderCount = metricValueBuilderCount.WithValue(count); foreach (var label in labels) { metricValueBuilderCount.WithLabel(label.Key, label.Value.ToString()); } long totalCount = 0; foreach (var bucket in buckets) { totalCount += bucket.Count; var metricValueBuilderBuckets = builder.AddValue(); metricValueBuilderBuckets.WithName(metricName + PrometheusHistogramBucketPostFix); metricValueBuilderBuckets = metricValueBuilderBuckets.WithValue(totalCount); foreach (var label in labels) { metricValueBuilderBuckets.WithLabel(label.Key, label.Value.ToString()); } var bucketName = double.IsPositiveInfinity(bucket.HighBoundary) ? PrometheusHistogramBucketLabelPositiveInfinity : bucket.HighBoundary.ToString(CultureInfo.InvariantCulture); metricValueBuilderBuckets.WithLabel(PrometheusHistogramBucketLabelLessThan, bucketName); } builder.Write(writer); }
private void WorkerThread() { this.httpListener.Start(); try { while (!this.tokenSource.IsCancellationRequested) { var ctxTask = this.httpListener.GetContextAsync(); ctxTask.Wait(this.tokenSource.Token); var ctx = ctxTask.Result; ctx.Response.StatusCode = 200; ctx.Response.ContentType = PrometheusMetricBuilder.ContentType; using var output = ctx.Response.OutputStream; using var writer = new StreamWriter(output); foreach (var metric in this.exporter.GetAndClearDoubleMetrics()) { var labels = metric.Labels; var builder = new PrometheusMetricBuilder() .WithName(metric.MetricName) .WithDescription(metric.MetricDescription); switch (metric.AggregationType) { case AggregationType.DoubleSum: { var doubleSum = metric.Data as SumData <double>; var doubleValue = doubleSum.Sum; builder = builder.WithType("counter"); foreach (var label in labels) { var metricValueBuilder = builder.AddValue(); metricValueBuilder = metricValueBuilder.WithValue(doubleValue); metricValueBuilder.WithLabel(label.Key, label.Value); } builder.Write(writer); break; } case AggregationType.LongSum: { // This cannot occcur as we are iterating Double metrics. // TODO: report error break; } case AggregationType.Summary: { // Not supported yet. break; } } } foreach (var metric in this.exporter.GetAndClearLongMetrics()) { var labels = metric.Labels; var builder = new PrometheusMetricBuilder() .WithName(metric.MetricName) .WithDescription(metric.MetricDescription); switch (metric.AggregationType) { case AggregationType.DoubleSum: { // This cannot occcur as we are iterating Long metrics. // TODO: report error break; } case AggregationType.LongSum: { var longSum = metric.Data as SumData <long>; var longValue = longSum.Sum; builder = builder.WithType("counter"); foreach (var label in labels) { var metricValueBuilder = builder.AddValue(); metricValueBuilder = metricValueBuilder.WithValue(longValue); metricValueBuilder.WithLabel(label.Key, label.Value); } builder.Write(writer); break; } case AggregationType.Summary: { // Not supported yet. break; } } } } } catch (OperationCanceledException) { // this will happen when cancellation will be requested } catch (Exception) { // TODO: report error } finally { this.httpListener.Stop(); this.httpListener.Close(); } }
/// <summary> /// Serialize to Prometheus Format. /// </summary> /// <param name="exporter">Prometheus Exporter.</param> /// <param name="writer">StreamWriter to write to.</param> public static void WriteMetricsCollection(this PrometheusExporter exporter, StreamWriter writer) { foreach (var metric in exporter.GetAndClearDoubleMetrics()) { var labels = metric.Labels; var builder = new PrometheusMetricBuilder() .WithName(metric.MetricName) .WithDescription(metric.MetricDescription); switch (metric.AggregationType) { case AggregationType.DoubleSum: { var doubleSum = metric.Data as SumData <double>; var doubleValue = doubleSum.Sum; builder = builder.WithType("counter"); foreach (var label in labels) { var metricValueBuilder = builder.AddValue(); metricValueBuilder = metricValueBuilder.WithValue(doubleValue); metricValueBuilder.WithLabel(label.Key, label.Value); } builder.Write(writer); break; } case AggregationType.Summary: { // Not supported yet. break; } } } foreach (var metric in exporter.GetAndClearLongMetrics()) { var labels = metric.Labels; var builder = new PrometheusMetricBuilder() .WithName(metric.MetricName) .WithDescription(metric.MetricDescription); switch (metric.AggregationType) { case AggregationType.LongSum: { var longSum = metric.Data as SumData <long>; var longValue = longSum.Sum; builder = builder.WithType("counter"); foreach (var label in labels) { var metricValueBuilder = builder.AddValue(); metricValueBuilder = metricValueBuilder.WithValue(longValue); metricValueBuilder.WithLabel(label.Key, label.Value); } builder.Write(writer); break; } case AggregationType.Summary: { // Not supported yet. break; } } } }