|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.Diagnostics.Metrics;
using System.Linq;
using Microsoft.Extensions.Diagnostics.Metrics.Testing;
using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Test.Helpers;
using Microsoft.Extensions.Logging.Testing;
using Microsoft.Extensions.Time.Testing;
using Microsoft.Shared.Instruments;
using Microsoft.TestUtilities;
using Moq;
using Xunit;
namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Disk.Test;
[OSSkipCondition(OperatingSystems.Windows | OperatingSystems.MacOSX, SkipReason = "Linux specific tests")]
public class LinuxSystemDiskMetricsTests
{
private readonly FakeLogger<LinuxSystemDiskMetrics> _fakeLogger = new();
[Fact]
public void Creates_Meter_With_Correct_Name()
{
using var meterFactory = new TestMeterFactory();
var diskStatsReaderMock = new Mock<IDiskStatsReader>();
var options = new ResourceMonitoringOptions { EnableSystemDiskIoMetrics = true };
_ = new LinuxSystemDiskMetrics(
_fakeLogger,
meterFactory,
Options.Options.Create(options),
TimeProvider.System,
diskStatsReaderMock.Object);
Meter meter = meterFactory.Meters.Single();
Assert.Equal(ResourceUtilizationInstruments.MeterName, meter.Name);
}
[Fact]
public void Test_MetricValues()
{
using var meterFactory = new TestMeterFactory();
var fakeTimeProvider = new FakeTimeProvider();
var options = new ResourceMonitoringOptions { EnableSystemDiskIoMetrics = true };
// Set up
var diskStatsReader = new FakeDiskStatsReader(new Dictionary<string, List<DiskStats>>
{
{
"sda", [
new DiskStats
{
DeviceName = "sda",
SectorsRead = 0,
SectorsWritten = 0,
ReadsCompleted = 0,
WritesCompleted = 0,
TimeIoMs = 0
},
new DiskStats
{
DeviceName = "sda",
SectorsRead = 500,
SectorsWritten = 1000,
ReadsCompleted = 600,
WritesCompleted = 1200,
TimeIoMs = 1234
},
new DiskStats
{
DeviceName = "sda",
SectorsRead = 700,
SectorsWritten = 1100,
ReadsCompleted = 800,
WritesCompleted = 1300,
TimeIoMs = 2234
},
new DiskStats
{
DeviceName = "sda",
SectorsRead = 1000,
SectorsWritten = 1600,
ReadsCompleted = 1300,
WritesCompleted = 1350,
TimeIoMs = 4444
}
]
},
{
"sdb", [
new DiskStats
{
DeviceName = "sdb",
SectorsRead = 200,
SectorsWritten = 300,
ReadsCompleted = 400,
WritesCompleted = 500,
TimeIoMs = 6000
},
new DiskStats
{
DeviceName = "sdb",
SectorsRead = 350,
SectorsWritten = 450,
ReadsCompleted = 550,
WritesCompleted = 650,
TimeIoMs = 7500
},
new DiskStats
{
DeviceName = "sdb",
SectorsRead = 400,
SectorsWritten = 500,
ReadsCompleted = 600,
WritesCompleted = 700,
TimeIoMs = 7500
},
new DiskStats
{
DeviceName = "sdb",
SectorsRead = 550,
SectorsWritten = 650,
ReadsCompleted = 750,
WritesCompleted = 850,
TimeIoMs = 9500
}
]
},
});
_ = new LinuxSystemDiskMetrics(
_fakeLogger,
meterFactory,
Options.Options.Create(options),
fakeTimeProvider,
diskStatsReader);
Meter meter = meterFactory.Meters.Single();
var readTag = new KeyValuePair<string, object?>("disk.io.direction", "read");
var writeTag = new KeyValuePair<string, object?>("disk.io.direction", "write");
var deviceTagSda = new KeyValuePair<string, object?>("system.device", "sda");
var deviceTagSdb = new KeyValuePair<string, object?>("system.device", "sdb");
using var diskIoCollector = new MetricCollector<long>(meter, ResourceUtilizationInstruments.SystemDiskIo);
using var operationCollector = new MetricCollector<long>(meter, ResourceUtilizationInstruments.SystemDiskOperations);
using var ioTimeCollector = new MetricCollector<double>(meter, ResourceUtilizationInstruments.SystemDiskIoTime);
// 1st measurement
diskIoCollector.RecordObservableInstruments();
operationCollector.RecordObservableInstruments();
ioTimeCollector.RecordObservableInstruments();
// Assert the 1st measurement
var diskIoMeasurement = diskIoCollector.GetMeasurementSnapshot();
Assert.Equal(4, diskIoMeasurement.Count);
Assert.Equal(256_000, diskIoMeasurement.Last(x => x.MatchesTags(readTag, deviceTagSda)).Value); // (500 - 0) * 512 = 256000
Assert.Equal(76_800, diskIoMeasurement.Last(x => x.MatchesTags(readTag, deviceTagSdb)).Value); // (350 - 200) * 512 = 76800
Assert.Equal(512_000, diskIoMeasurement.Last(x => x.MatchesTags(writeTag, deviceTagSda)).Value); // (1000 - 0) * 512 = 512000
Assert.Equal(76_800, diskIoMeasurement.Last(x => x.MatchesTags(writeTag, deviceTagSdb)).Value); // (450 - 300) * 512 = 76800
var operationMeasurement = operationCollector.GetMeasurementSnapshot();
Assert.Equal(4, operationMeasurement.Count);
Assert.Equal(600, operationMeasurement.Last(x => x.MatchesTags(readTag, deviceTagSda)).Value); // 600 - 0 = 600
Assert.Equal(150, operationMeasurement.Last(x => x.MatchesTags(readTag, deviceTagSdb)).Value); // 550 - 400 = 150
Assert.Equal(1200, operationMeasurement.Last(x => x.MatchesTags(writeTag, deviceTagSda)).Value); // 1200 - 0 = 1200
Assert.Equal(150, operationMeasurement.Last(x => x.MatchesTags(writeTag, deviceTagSdb)).Value); // 650 - 500 = 150
var ioTimeMeasurement = ioTimeCollector.GetMeasurementSnapshot();
Assert.Equal(2, ioTimeMeasurement.Count);
Assert.Equal(1.234, ioTimeMeasurement.Last(x => x.MatchesTags(deviceTagSda)).Value, 0.01); // (1234 - 0) / 1000 = 1.234
Assert.Equal(1.5, ioTimeMeasurement.Last(x => x.MatchesTags(deviceTagSdb)).Value, 0.01); // (7500 - 6000) / 1000 = 6.0
// 2nd measurement
fakeTimeProvider.Advance(TimeSpan.FromMinutes(1));
diskIoCollector.RecordObservableInstruments();
operationCollector.RecordObservableInstruments();
ioTimeCollector.RecordObservableInstruments();
// Assert the 2nd measurement
diskIoMeasurement = diskIoCollector.GetMeasurementSnapshot();
Assert.Equal(358_400, diskIoMeasurement.Last(x => x.MatchesTags(readTag, deviceTagSda)).Value); // (700 - 0) * 512 = 358400
Assert.Equal(102_400, diskIoMeasurement.Last(x => x.MatchesTags(readTag, deviceTagSdb)).Value); // (400 - 200) * 512 = 102400
Assert.Equal(563_200, diskIoMeasurement.Last(x => x.MatchesTags(writeTag, deviceTagSda)).Value); // (1100 - 0) * 512 = 563200
Assert.Equal(102_400, diskIoMeasurement.Last(x => x.MatchesTags(writeTag, deviceTagSdb)).Value); // (500 - 300) * 512 = 102400
operationMeasurement = operationCollector.GetMeasurementSnapshot();
Assert.Equal(800, operationMeasurement.Last(x => x.MatchesTags(readTag, deviceTagSda)).Value); // 800 - 0 = 800
Assert.Equal(200, operationMeasurement.Last(x => x.MatchesTags(readTag, deviceTagSdb)).Value); // 600 - 400 = 200
Assert.Equal(1300, operationMeasurement.Last(x => x.MatchesTags(writeTag, deviceTagSda)).Value); // 1300 - 0 = 1300
Assert.Equal(200, operationMeasurement.Last(x => x.MatchesTags(writeTag, deviceTagSdb)).Value); // 700 - 500 = 200
ioTimeMeasurement = ioTimeCollector.GetMeasurementSnapshot();
Assert.Equal(2.234, ioTimeMeasurement.Last(x => x.MatchesTags(deviceTagSda)).Value, 0.01); // (2234 - 0) / 1000 = 2.234
Assert.Equal(1.5, ioTimeMeasurement.Last(x => x.MatchesTags(deviceTagSdb)).Value, 0.01); // (7500 - 6000) / 1000 = 1.5
// 3rd measurement
fakeTimeProvider.Advance(TimeSpan.FromMinutes(1));
diskIoCollector.RecordObservableInstruments();
operationCollector.RecordObservableInstruments();
ioTimeCollector.RecordObservableInstruments();
// Assert the 3rd measurement
diskIoMeasurement = diskIoCollector.GetMeasurementSnapshot();
Assert.Equal(512_000, diskIoMeasurement.Last(x => x.MatchesTags(readTag, deviceTagSda)).Value); // (1000 - 0) * 512 = 512000
Assert.Equal(179_200, diskIoMeasurement.Last(x => x.MatchesTags(readTag, deviceTagSdb)).Value); // (550 - 200) * 512 = 179200
Assert.Equal(819_200, diskIoMeasurement.Last(x => x.MatchesTags(writeTag, deviceTagSda)).Value); // (1600 - 0) * 512 = 819200
Assert.Equal(179_200, diskIoMeasurement.Last(x => x.MatchesTags(writeTag, deviceTagSdb)).Value); // (650 - 300) * 512 = 179200
operationMeasurement = operationCollector.GetMeasurementSnapshot();
Assert.Equal(1300, operationMeasurement.Last(x => x.MatchesTags(readTag, deviceTagSda)).Value); // 1300 - 0 = 1300
Assert.Equal(350, operationMeasurement.Last(x => x.MatchesTags(readTag, deviceTagSdb)).Value); // 750 - 400 = 350
Assert.Equal(1350, operationMeasurement.Last(x => x.MatchesTags(writeTag, deviceTagSda)).Value); // 1350 - 0 = 1350
Assert.Equal(350, operationMeasurement.Last(x => x.MatchesTags(writeTag, deviceTagSdb)).Value); // 850 - 500 = 350
ioTimeMeasurement = ioTimeCollector.GetMeasurementSnapshot();
Assert.Equal(4.444, ioTimeMeasurement.Last(x => x.MatchesTags(deviceTagSda)).Value, 0.01); // (4444 - 0) / 1000 = 4.444
Assert.Equal(3.5, ioTimeMeasurement.Last(x => x.MatchesTags(deviceTagSdb)).Value, 0.01); // (9500 - 6000) / 1000 = 3.5
}
}
|