Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ Notes](../../RELEASENOTES.md).

## Unreleased

* Fixed scrape response cache freshness using monotonic time so it is not
affected by NTP system clock adjustments.
([#7253](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7253))

* **Breaking Change** Removed `DisableTimestamp` property from
`PrometheusAspNetCoreOptions`.
([#7176](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7176))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
<Compile Include="$(RepoRoot)\src\Shared\ExceptionExtensions.cs" Link="Includes\ExceptionExtensions.cs" />
<Compile Include="$(RepoRoot)\src\Shared\Guard.cs" Link="Includes\Guard.cs" />
<Compile Include="$(RepoRoot)\src\Shared\Shims\NullableAttributes.cs" Link="Includes\Shims\NullableAttributes.cs" />
<Compile Include="$(RepoRoot)\src\Shared\StopwatchExtensions.cs" Link="Includes\StopwatchExtensions.cs" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ Notes](../../RELEASENOTES.md).

## Unreleased

* Fixed scrape response cache freshness using monotonic time so it is not
affected by NTP system clock adjustments.
([#7253](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7253))

* Added `Host` and `Port` properties on `PrometheusHttpListenerOptions`
for configuring the HTTP listener endpoint. The
`PrometheusHttpListenerOptions.UriPrefixes` property is now obsolete and
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

using System.Diagnostics;
using System.Runtime.CompilerServices;
using OpenTelemetry.Metrics;

Expand All @@ -11,7 +12,8 @@ internal sealed class PrometheusCollectionManager
private const int MaxCachedMetrics = 1024;

private readonly PrometheusExporter exporter;
private readonly int scrapeResponseCacheDurationMilliseconds;
private readonly TimeSpan scrapeResponseCacheDuration;
private readonly long baseTimestamp = Stopwatch.GetTimestamp();
private readonly PrometheusExporter.ExportFunc onCollectRef;
private readonly Dictionary<Metric, PrometheusMetric> metricsCache;
private readonly HashSet<string> scopes;
Expand All @@ -24,21 +26,26 @@ internal sealed class PrometheusCollectionManager
private int globalLockState;
private DateTime? previousPlainTextDataViewGeneratedAtUtc;
private DateTime? previousOpenMetricsDataViewGeneratedAtUtc;
private TimeSpan previousPlainTextDataViewGeneratedAtElapsed;
private TimeSpan previousOpenMetricsDataViewGeneratedAtElapsed;
private int readerCount;
private bool collectionRunning;
private TaskCompletionSource<CollectionResponse>? collectionTcs;

public PrometheusCollectionManager(PrometheusExporter exporter)
{
this.exporter = exporter;
this.scrapeResponseCacheDurationMilliseconds = this.exporter.ScrapeResponseCacheDurationMilliseconds;
this.scrapeResponseCacheDuration = TimeSpan.FromMilliseconds(this.exporter.ScrapeResponseCacheDurationMilliseconds);
this.onCollectRef = this.OnCollect;
this.metricsCache = [];
this.scopes = [];
this.GetElapsedTime = () => Stopwatch.GetElapsedTime(this.baseTimestamp);
}

internal Func<DateTime> UtcNow { get; set; } = static () => DateTime.UtcNow;

internal Func<TimeSpan> GetElapsedTime { get; set; }

#if NET
public ValueTask<CollectionResponse> EnterCollect(bool openMetricsRequested)
#else
Expand All @@ -51,15 +58,17 @@ public Task<CollectionResponse> EnterCollect(bool openMetricsRequested)

try
{
// If we are within {ScrapeResponseCacheDurationMilliseconds} of the
// last successful collect, return the previous view.
previousDataViewGeneratedAtUtc = openMetricsRequested
? this.previousOpenMetricsDataViewGeneratedAtUtc
: this.previousPlainTextDataViewGeneratedAtUtc;

var previousDataViewGeneratedAtElapsed = openMetricsRequested
? this.previousOpenMetricsDataViewGeneratedAtElapsed
: this.previousPlainTextDataViewGeneratedAtElapsed;

if (previousDataViewGeneratedAtUtc.HasValue
&& this.scrapeResponseCacheDurationMilliseconds > 0
&& previousDataViewGeneratedAtUtc.Value.AddMilliseconds(this.scrapeResponseCacheDurationMilliseconds) >= this.UtcNow())
&& this.scrapeResponseCacheDuration > TimeSpan.Zero
&& this.GetElapsedTime() - previousDataViewGeneratedAtElapsed < this.scrapeResponseCacheDuration)
{
#if NET
return new ValueTask<CollectionResponse>(new CollectionResponse(this.previousOpenMetricsDataView, this.previousPlainTextDataView, previousDataViewGeneratedAtUtc.Value, fromCache: true));
Expand Down Expand Up @@ -105,14 +114,17 @@ public Task<CollectionResponse> EnterCollect(bool openMetricsRequested)
if (result)
{
var generatedAt = this.UtcNow();
var generatedAtElapsed = this.GetElapsedTime();

if (openMetricsRequested)
{
this.previousOpenMetricsDataViewGeneratedAtUtc = generatedAt;
this.previousOpenMetricsDataViewGeneratedAtElapsed = generatedAtElapsed;
}
else
{
this.previousPlainTextDataViewGeneratedAtUtc = generatedAt;
this.previousPlainTextDataViewGeneratedAtElapsed = generatedAtElapsed;
}

previousDataViewGeneratedAtUtc = openMetricsRequested
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<Compile Include="$(RepoRoot)\src\Shared\MathHelper.cs" Link="Includes\MathHelper.cs" />
<Compile Include="$(RepoRoot)\src\Shared\Shims\Lock.cs" Link="Includes\Shims\Lock.cs" />
<Compile Include="$(RepoRoot)\src\Shared\Shims\NullableAttributes.cs" Link="Includes\Shims\NullableAttributes.cs" />
<Compile Include="$(RepoRoot)\src\Shared\StopwatchExtensions.cs" Link="Includes\StopwatchExtensions.cs" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,13 @@ public async Task EnterExitCollectTest(int scrapeResponseCacheDurationMillisecon
return result;
};

var utcNow = DateTime.UtcNow;
var startUtc = DateTime.UtcNow;
var utcNow = startUtc;

if (cacheEnabled)
{
// Override the cache to ensure the cache is always seen again during its validity period.
exporter.CollectionManager.UtcNow = () => utcNow;
exporter.CollectionManager.GetElapsedTime = () => utcNow - startUtc;
}

var counter = meter.CreateCounter<int>("counter_int", description: "Prometheus help text goes here \n escaping.");
Expand Down
Loading