Skip to content

Commit

Permalink
Merge branch 'master' into cijothomas/activity3adapter1a_alternate
Browse files Browse the repository at this point in the history
  • Loading branch information
cijothomas committed Jun 2, 2020
2 parents 036a9bb + 4ed65d3 commit 382d85f
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 160 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,31 +23,31 @@ namespace OpenTelemetry.Exporter.Prometheus.Implementation
{
internal class PrometheusMetricBuilder
{
public static readonly string ContentType = "text/plain; version = 0.0.4";
public const string ContentType = "text/plain; version = 0.0.4";

private static readonly char[] FirstCharacterNameCharset = new char[]
private static readonly char[] FirstCharacterNameCharset =
{
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'_', ':',
};

private static readonly char[] NameCharset = new char[]
private static readonly char[] NameCharset =
{
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'_', ':',
};

private static readonly char[] FirstCharacterLabelCharset = new char[]
private static readonly char[] FirstCharacterLabelCharset =
{
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'_',
};

private static readonly char[] LabelCharset = new char[]
private static readonly char[] LabelCharset =
{
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
Expand Down Expand Up @@ -138,6 +138,8 @@ public void Write(StreamWriter writer)
// ] value [ timestamp ]
// In the sample syntax:

var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();

foreach (var m in this.values)
{
// metric_name and label_name carry the usual Prometheus expression language restrictions.
Expand All @@ -150,27 +152,7 @@ public void Write(StreamWriter writer)
if (m.Labels.Count > 0)
{
writer.Write(@"{");
var isFirst = true;

foreach (var l in m.Labels)
{
if (isFirst)
{
isFirst = false;
}
else
{
writer.Write(",");
}

var safeKey = GetSafeLabelName(l.Item1);
var safeValue = GetSafeLabelValue(l.Item2);
writer.Write(safeKey);
writer.Write("=\"");
writer.Write(safeValue);
writer.Write("\"");
}

writer.Write(string.Join(",", m.Labels.Select(x => GetLabelAndValue(x.Item1, x.Item2))));
writer.Write(@"}");
}

Expand All @@ -183,71 +165,23 @@ public void Write(StreamWriter writer)

// The timestamp is an int64 (milliseconds since epoch, i.e. 1970-01-01 00:00:00 UTC, excluding
// leap seconds), represented as required by Go's ParseInt() function.
writer.Write(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString());
writer.Write(now);

// Prometheus' text-based format is line oriented. Lines are separated
// by a line feed character (\n). The last line must end with a line
// feed character. Empty lines are ignored.
writer.Write("\n");
}
}

private static string GetSafeMetricName(string name)
{
// https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels
//
// Metric names and labels
// Every time series is uniquely identified by its metric name and a set of key-value pairs, also known as labels.
// The metric name specifies the general feature of a system that is measured (e.g. http_requests_total - the total number of HTTP requests received). It may contain ASCII letters and digits, as well as underscores and colons. It must match the regex [a-zA-Z_:][a-zA-Z0-9_:]*.
// Note: The colons are reserved for user defined recording rules. They should not be used by exporters or direct instrumentation.
// Labels enable Prometheus's dimensional data model: any given combination of labels for the same metric name identifies a particular dimensional instantiation of that metric (for example: all HTTP requests that used the method POST to the /api/tracks handler). The query language allows filtering and aggregation based on these dimensions. Changing any label value, including adding or removing a label, will create a new time series.
// Label names may contain ASCII letters, numbers, as well as underscores. They must match the regex [a-zA-Z_][a-zA-Z0-9_]*. Label names beginning with __ are reserved for internal use.
// Label values may contain any Unicode characters.

var sb = new StringBuilder();

if (!string.IsNullOrEmpty(name))
static string GetLabelAndValue(string label, string value)
{
var firstChar = name[0];
if (FirstCharacterNameCharset.Contains(firstChar))
{
sb.Append(firstChar);
}
else
{
firstChar = firstChar.ToString().ToLowerInvariant()[0];

if (FirstCharacterNameCharset.Contains(firstChar))
{
sb.Append(firstChar);
}
else
{
// fallback character
sb.Append('_');
}
}
var safeKey = GetSafeLabelName(label);
var safeValue = GetSafeLabelValue(value);
return $"{safeKey}=\"{safeValue}\"";
}

for (var i = 1; i < name.Length; ++i)
{
var c = name[i];

if (NameCharset.Contains(c))
{
sb.Append(c);
}
else
{
// fallback character
sb.Append('_');
}
}

return sb.ToString();
}

private static string GetSafeLabelName(string name)
private static string GetSafeName(string name, char[] firstCharNameCharset, char[] charNameCharset)
{
// https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels
//
Expand All @@ -260,48 +194,26 @@ private static string GetSafeLabelName(string name)
// Label values may contain any Unicode characters.

var sb = new StringBuilder();
var firstChar = name[0];

if (!string.IsNullOrEmpty(name))
{
var firstChar = name[0];
if (FirstCharacterLabelCharset.Contains(firstChar))
{
sb.Append(firstChar);
}
else
{
firstChar = firstChar.ToString().ToLowerInvariant()[0];

if (FirstCharacterLabelCharset.Contains(firstChar))
{
sb.Append(firstChar);
}
else
{
// fallback character
sb.Append('_');
}
}
}
sb.Append(firstCharNameCharset.Contains(firstChar)
? firstChar
: GetSafeChar(char.ToLowerInvariant(firstChar), firstCharNameCharset));

for (var i = 1; i < name.Length; ++i)
{
var c = name[i];

if (LabelCharset.Contains(c))
{
sb.Append(c);
}
else
{
// fallback character
sb.Append('_');
}
sb.Append(GetSafeChar(name[i], charNameCharset));
}

return sb.ToString();

static char GetSafeChar(char c, char[] charset) => charset.Contains(c) ? c : '_';
}

private static string GetSafeMetricName(string name) => GetSafeName(name, FirstCharacterNameCharset, NameCharset);

private static string GetSafeLabelName(string name) => GetSafeName(name, FirstCharacterLabelCharset, LabelCharset);

private static string GetSafeLabelValue(string value)
{
// label_value can be any sequence of UTF-8 characters, but the backslash
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ private static void WriteSum(StreamWriter writer, PrometheusMetricBuilder builde
foreach (var label in labels)
{
/* For Summary we emit one row for Sum, Count, Min, Max.
Min,Max exportes as quantile 0 and 1.
Min,Max exports as quantile 0 and 1.
In future, when OT implements more aggregation algorithms,
this section will need to be revisited.
Sample output:
Expand All @@ -149,27 +149,24 @@ private static void WriteSum(StreamWriter writer, PrometheusMetricBuilder builde
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.AddValue()
.WithName(metricName + PrometheusSummarySumPostFix)
.WithLabel(label.Key, label.Value)
.WithValue(sum);
builder.AddValue()
.WithName(metricName + PrometheusSummaryCountPostFix)
.WithLabel(label.Key, label.Value)
.WithValue(count);
builder.AddValue()
.WithName(metricName)
.WithLabel(label.Key, label.Value)
.WithLabel(PrometheusSummaryQuantileLabelName, PrometheusSummaryQuantileLabelValueForMin)
.WithValue(min);
builder.AddValue()
.WithName(metricName)
.WithLabel(label.Key, label.Value)
.WithLabel(PrometheusSummaryQuantileLabelName, PrometheusSummaryQuantileLabelValueForMax)
.WithValue(max);
}

builder.Write(writer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public void Start(CancellationToken token = default)
new CancellationTokenSource() :
CancellationTokenSource.CreateLinkedTokenSource(token);

this.workerThread = Task.Factory.StartNew((Action)this.WorkerThread, TaskCreationOptions.LongRunning);
this.workerThread = Task.Factory.StartNew(this.WorkerThread, TaskCreationOptions.LongRunning);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ namespace OpenTelemetry.Exporter.Prometheus
/// </summary>
public class PrometheusExporterMiddleware
{
private readonly RequestDelegate next;
private readonly PrometheusExporter exporter;

/// <summary>
Expand All @@ -37,7 +36,6 @@ public class PrometheusExporterMiddleware
/// <param name="exporter">The <see cref="PrometheusExporter"/> instance.</param>
public PrometheusExporterMiddleware(RequestDelegate next, PrometheusExporter exporter)
{
this.next = next ?? throw new ArgumentNullException(nameof(next));
this.exporter = exporter ?? throw new ArgumentNullException(nameof(exporter));
}

Expand All @@ -46,7 +44,7 @@ public PrometheusExporterMiddleware(RequestDelegate next, PrometheusExporter exp
/// </summary>
/// <param name="httpContext"> context. </param>
/// <returns>Task. </returns>
public async Task InvokeAsync(HttpContext httpContext)
public Task InvokeAsync(HttpContext httpContext)
{
if (httpContext is null)
{
Expand All @@ -55,7 +53,7 @@ public async Task InvokeAsync(HttpContext httpContext)

var result = this.exporter.GetMetricsCollection();

await httpContext.Response.WriteAsync(result).ConfigureAwait(false);
return httpContext.Response.WriteAsync(result);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

#if NETSTANDARD2_0

using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;

Expand All @@ -39,8 +38,8 @@ public static IApplicationBuilder UsePrometheus(this IApplicationBuilder app)
var options = app.ApplicationServices.GetService(typeof(PrometheusExporterOptions)) as PrometheusExporterOptions;
var path = new PathString(options?.Url ?? DefaultPath);
return app.Map(
new PathString(options.Url),
(app) => app.UseMiddleware<PrometheusExporterMiddleware>());
new PathString(path),
builder => builder.UseMiddleware<PrometheusExporterMiddleware>());
}
}
}
Expand Down

0 comments on commit 382d85f

Please sign in to comment.