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;
                    }
                    }
                }
            }
        }
Beispiel #4
0
        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);
        }
Beispiel #8
0
        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();
            }
        }
Beispiel #9
0
        /// <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;
                }
                }
            }
        }