dotnet / dotnet/docs

metrics-instrumentation missing discussion of RecordObservableInstruments for unit testing

Open
#39,347 0 comments 0 reactions 0 assignees View on GitHub
:watch: Not Triaged dotnet-fundamentals/svc
Dominant language
No language data
Stars
4.8k
Forks
6.1k
Avg merge
15h 21m
Merged PRs (30d)
370

Description

### Type of issue

Missing information

### Description

This documentation makes no mention of the need to call `MetricCollector.RecordObservableInstruments` when unit testing something like an `ObservableGauge`. The documentation on this method is effectively missing as well. It took me most of the day to figure out how to test an ObservableGauge.

For those currently struggling, the following tests may offer a little more insight

```c#
public class DistributedLockTests
{
private const string _lockId = "lockId";
private readonly MetricCollector _averageLockDurationGaugeCollector;
private readonly DistributedLock _distributedLock;
private readonly MetricCollector _lockDurationHistogramCollector;
private readonly FakeTimeProvider _timeProvider = new();

public DistributedLockTests()
{
ServiceCollection serviceCollection = [];
serviceCollection.AddMetrics();
ServiceProvider provider = serviceCollection.BuildServiceProvider();
IMeterFactory meterFactory = provider.GetService() ??
throw new InvalidOperationException("Could not provide meter factory.");
_distributedLock = new DistributedLock(_lockId, meterFactory, _timeProvider);
_lockDurationHistogramCollector = new MetricCollector(
_distributedLock.LockDurationMillisecondsHistogram,
_timeProvider);
_averageLockDurationGaugeCollector = new MetricCollector(
_distributedLock.AverageLockDurationMillisecondsGauge,
_timeProvider);
}

[Fact]
public async Task Release_WhenALockWasPreviouslyObtained_ComputesAverageLockTime()
{
// Arrange

// Act
await AcquireWaitAndReleaseLock(TimeSpan.FromMilliseconds(100));
await AcquireWaitAndReleaseLock(TimeSpan.FromMilliseconds(200));

// Assert
_distributedLock.AverageLockDurationMilliseconds.Should().Be(150);
IReadOnlyList> lockDurations =
_lockDurationHistogramCollector.GetMeasurementSnapshot();

// There is no public constructor for CollectedMeasurement, so we can only test individual properties.
ExpectMeasurement(lockDurations[0], 100.0, "2000-01-01T00:00:00.100Z");
ExpectMeasurement(lockDurations[1], 200.0, "2000-01-01T00:00:00.300Z");
_averageLockDurationGaugeCollector.RecordObservableInstruments();
IReadOnlyList> averageLockDurations =
_averageLockDurationGaugeCollector.GetMeasurementSnapshot();
averageLockDurations.Count.Should().Be(1);
averageLockDurations[0].Value.Should().Be(150.0);
averageLockDurations[0].Timestamp.Should().BeExactly(
DateTimeOffset.Parse("2000-01-01T00:00:00.300Z", CultureInfo.InvariantCulture));
}

private async Task AcquireWaitAndReleaseLock(TimeSpan timeSpan)
{
await _distributedLock.WaitAsync();
_distributedLock.RecordSharedLockAcquisitionTime();
_timeProvider.Advance(timeSpan);
_distributedLock.Release();
}

private static void ExpectMeasurement(CollectedMeasurement measurement, T value, string timestamp) where T : struct
{
measurement.Value.Should().Be(value);
measurement.Timestamp.Should().BeExactly(DateTimeOffset.Parse(timestamp, CultureInfo.InvariantCulture));
}
}
```

### Page URL

https://learn.microsoft.com/en-us/dotnet/core/diagnostics/metrics-instrumentation

### Content source URL

https://github.com/dotnet/docs/blob/main/docs/core/diagnostics/metrics-instrumentation.md

### Document Version Independent Id

02ec1bf2-d0fe-dac5-b2c1-45d607430b06

### Article author

@tommcdon

### Metadata

* ID: 61024acd-c2e8-291a-3007-7f09a1857690
* Service: **dotnet-fundamentals**

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.