Skip to content

Commit

Permalink
Working with prometheus now
Browse files Browse the repository at this point in the history
  • Loading branch information
robertcoltheart committed Nov 30, 2023
1 parent 74014ac commit 9526647
Show file tree
Hide file tree
Showing 15 changed files with 259 additions and 168 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ Microsoft.AspNetCore.Builder.PrometheusExporterApplicationBuilderExtensions
Microsoft.AspNetCore.Builder.PrometheusExporterEndpointRouteBuilderExtensions
OpenTelemetry.Exporter.PrometheusAspNetCoreOptions
OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.PrometheusAspNetCoreOptions() -> void
OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.ScopeInfoEnabled.get -> bool
OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.ScopeInfoEnabled.set -> void
OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.OpenMetricsEnabled.get -> bool
OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.OpenMetricsEnabled.set -> void
OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.ScrapeEndpointPath.get -> string
OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.ScrapeEndpointPath.set -> void
OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.ScrapeResponseCacheDurationMilliseconds.get -> int
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ public int ScrapeResponseCacheDurationMilliseconds
}

/// <summary>
/// Gets or sets a value indicating whether to export metric scope info. Default value: true.
/// Gets or sets a value indicating whether to export OpenMetrics compatible scrape responses. Default value: true.
/// </summary>
public bool ScopeInfoEnabled
public bool OpenMetricsEnabled
{
get => this.ExporterOptions.ScopeInfoEnabled;
set => this.ExporterOptions.ScopeInfoEnabled = value;
get => this.ExporterOptions.OpenMetricsEnabled;
set => this.ExporterOptions.OpenMetricsEnabled = value;
}

internal PrometheusExporterOptions ExporterOptions { get; } = new();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

using System.Diagnostics;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;
using OpenTelemetry.Exporter.Prometheus;
using OpenTelemetry.Internal;
using OpenTelemetry.Metrics;
Expand All @@ -27,6 +29,8 @@ namespace OpenTelemetry.Exporter;
/// </summary>
internal sealed class PrometheusExporterMiddleware
{
private const string OpenMetricsMediaType = "application/openmetrics-text";

private readonly PrometheusExporter exporter;

/// <summary>
Expand Down Expand Up @@ -75,7 +79,14 @@ public async Task InvokeAsync(HttpContext httpContext)
#else
response.Headers.Add("Last-Modified", collectionResponse.GeneratedAtUtc.ToString("R"));
#endif
response.ContentType = "text/plain; charset=utf-8; version=0.0.4";
if (this.exporter.OpenMetricsEnabled && this.AcceptsOpenMetrics(httpContext.Request))
{
response.ContentType = "application/openmetrics-text; version=1.0.0; charset=utf-8";
}
else
{
response.ContentType = "text/plain; charset=utf-8; version=0.0.4";
}

await response.Body.WriteAsync(collectionResponse.View.Array, 0, collectionResponse.View.Count).ConfigureAwait(false);
}
Expand All @@ -102,4 +113,28 @@ public async Task InvokeAsync(HttpContext httpContext)

this.exporter.OnExport = null;
}

private bool AcceptsOpenMetrics(HttpRequest request)
{
var requestAccept = request.Headers[HeaderNames.Accept];

if (StringValues.IsNullOrEmpty(requestAccept))
{
return false;
}

var acceptTypes = requestAccept.ToString().Split(',');

foreach (var acceptType in acceptTypes)
{
var acceptSubType = acceptType.Split(';').FirstOrDefault()?.Trim();

if (acceptSubType == OpenMetricsMediaType)
{
return true;
}
}

return false;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
OpenTelemetry.Exporter.PrometheusHttpListenerOptions
OpenTelemetry.Exporter.PrometheusHttpListenerOptions.OpenMetricsEnabled.get -> bool
OpenTelemetry.Exporter.PrometheusHttpListenerOptions.OpenMetricsEnabled.set -> void
OpenTelemetry.Exporter.PrometheusHttpListenerOptions.UriPrefixes.get -> System.Collections.Generic.IReadOnlyCollection<string>
OpenTelemetry.Exporter.PrometheusHttpListenerOptions.UriPrefixes.set -> void
OpenTelemetry.Exporter.PrometheusHttpListenerOptions.PrometheusHttpListenerOptions() -> void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ private ExportResult OnCollect(Batch<Metric> metrics)

try
{
if (this.exporter.ScopeInfoEnabled)
if (this.exporter.OpenMetricsEnabled)
{
this.scopes.Clear();

Expand Down Expand Up @@ -229,7 +229,7 @@ private ExportResult OnCollect(Batch<Metric> metrics)
{
try
{
cursor = PrometheusSerializer.WriteMetric(this.buffer, cursor, metric, this.GetPrometheusMetric(metric), this.exporter.ScopeInfoEnabled);
cursor = PrometheusSerializer.WriteMetric(this.buffer, cursor, metric, this.GetPrometheusMetric(metric), this.exporter.OpenMetricsEnabled);
break;
}
catch (IndexOutOfRangeException)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public PrometheusExporter(PrometheusExporterOptions options)
Guard.ThrowIfNull(options);

this.ScrapeResponseCacheDurationMilliseconds = options.ScrapeResponseCacheDurationMilliseconds;
this.ScopeInfoEnabled = options.ScopeInfoEnabled;
this.OpenMetricsEnabled = options.OpenMetricsEnabled;

this.CollectionManager = new PrometheusCollectionManager(this);
}
Expand All @@ -64,7 +64,7 @@ internal Func<Batch<Metric>, ExportResult> OnExport

internal int ScrapeResponseCacheDurationMilliseconds { get; }

internal bool ScopeInfoEnabled { get; }
internal bool OpenMetricsEnabled { get; }

/// <inheritdoc/>
public override ExportResult Export(in Batch<Metric> metrics)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public int ScrapeResponseCacheDurationMilliseconds
}

/// <summary>
/// Gets or sets a value indicating whether to export metric scope info. Default value: true.
/// Gets or sets a value indicating whether to export OpenMetrics compatible scrape responses. Default value: true.
/// </summary>
public bool ScopeInfoEnabled { get; set; } = true;
public bool OpenMetricsEnabled { get; set; } = true;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using System.Globalization;
using System.Runtime.CompilerServices;
using OpenTelemetry.Internal;
using OpenTelemetry.Metrics;

namespace OpenTelemetry.Exporter.Prometheus;

Expand Down Expand Up @@ -347,7 +348,69 @@ public static int WriteScopeInfo(byte[] buffer, int cursor, string scopeName)
buffer[cursor++] = unchecked((byte)' ');
buffer[cursor++] = unchecked((byte)'1');
buffer[cursor++] = ASCII_LINEFEED;
buffer[cursor++] = ASCII_LINEFEED;

return cursor;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int WriteTimestamp(byte[] buffer, int cursor, long value, bool openMetricsEnabled)
{
if (openMetricsEnabled)
{
cursor = WriteLong(buffer, cursor, value / 1000);
buffer[cursor++] = unchecked((byte)'.');

long millis = value % 1000;

if (millis < 100)
{
buffer[cursor++] = unchecked((byte)'0');
}

if (millis < 10)
{
buffer[cursor++] = unchecked((byte)'0');
}

return WriteLong(buffer, cursor, millis);
}

return WriteLong(buffer, cursor, value);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int WriteTags(byte[] buffer, int cursor, Metric metric, ReadOnlyTagCollection tags, bool openMetricsEnabled, bool writeEnclosingBraces = true)
{
if (tags.Count > 0 || openMetricsEnabled)
{
if (writeEnclosingBraces)
{
buffer[cursor++] = unchecked((byte)'{');
}

if (openMetricsEnabled)
{
cursor = WriteLabel(buffer, cursor, "otel_scope_name", metric.MeterName);
buffer[cursor++] = unchecked((byte)',');

if (!string.IsNullOrEmpty(metric.MeterVersion))
{
cursor = WriteLabel(buffer, cursor, "otel_scope_version", metric.MeterVersion);
buffer[cursor++] = unchecked((byte)',');
}
}

foreach (var tag in tags)
{
cursor = WriteLabel(buffer, cursor, tag.Key, tag.Value);
buffer[cursor++] = unchecked((byte)',');
}

if (writeEnclosingBraces)
{
buffer[cursor - 1] = unchecked((byte)'}'); // Note: We write the '}' over the last written comma, which is extra.
}
}

return cursor;
}
Expand Down
Loading

0 comments on commit 9526647

Please sign in to comment.