diff --git a/.editorconfig b/.editorconfig
index e9277261794..5f172a29b3a 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -160,6 +160,9 @@ dotnet_diagnostic.RS0041.severity = suggestion
# CA1515: Disable making types internal for Tests classes. It is required by xunit
dotnet_diagnostic.CA1515.severity = none
+# CA2007: Disable Consider calling ConfigureAwait on the awaited task. It is not working with xunit
+dotnet_diagnostic.CA2007.severity = none
+
[**/obj/**.cs]
generated_code = true
diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj
index f6a49fe6a64..c0b202cc640 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj
+++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj
@@ -7,6 +7,7 @@
$(PackageTags);prometheus;metrics
coreunstable-
$(DefineConstants);PROMETHEUS_ASPNETCORE
+ latest-all
diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterApplicationBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterApplicationBuilderExtensions.cs
index 38559e6b201..92bef6f1b59 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterApplicationBuilderExtensions.cs
+++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterApplicationBuilderExtensions.cs
@@ -99,6 +99,8 @@ public static IApplicationBuilder UseOpenTelemetryPrometheusScrapingEndpoint(
Action? configureBranchedPipeline,
string? optionsName)
{
+ Guard.ThrowIfNull(app);
+
// Note: Order is important here. MeterProvider is accessed before
// GetOptions so that any changes made to
// PrometheusAspNetCoreOptions in deferred AddPrometheusExporter
@@ -114,7 +116,7 @@ public static IApplicationBuilder UseOpenTelemetryPrometheusScrapingEndpoint(
path = options.ScrapeEndpointPath ?? PrometheusAspNetCoreOptions.DefaultScrapeEndpointPath;
}
- if (!path.StartsWith("/"))
+ if (!path.StartsWith('/'))
{
path = $"/{path}";
}
diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterEndpointRouteBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterEndpointRouteBuilderExtensions.cs
index 45639b378fc..6604935ebf0 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterEndpointRouteBuilderExtensions.cs
+++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterEndpointRouteBuilderExtensions.cs
@@ -69,6 +69,8 @@ public static IEndpointConventionBuilder MapPrometheusScrapingEndpoint(
Action? configureBranchedPipeline,
string? optionsName)
{
+ Guard.ThrowIfNull(endpoints);
+
var builder = endpoints.CreateApplicationBuilder();
// Note: Order is important here. MeterProvider is accessed before
@@ -84,7 +86,7 @@ public static IEndpointConventionBuilder MapPrometheusScrapingEndpoint(
path = options.ScrapeEndpointPath ?? PrometheusAspNetCoreOptions.DefaultScrapeEndpointPath;
}
- if (!path.StartsWith("/"))
+ if (!path.StartsWith('/'))
{
path = $"/{path}";
}
diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMeterProviderBuilderExtensions.cs
index f73455d3b08..e3567d4ad63 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMeterProviderBuilderExtensions.cs
+++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMeterProviderBuilderExtensions.cs
@@ -62,9 +62,11 @@ public static MeterProviderBuilder AddPrometheusExporter(
});
}
- private static MetricReader BuildPrometheusExporterMetricReader(PrometheusAspNetCoreOptions options)
+ private static BaseExportingMetricReader BuildPrometheusExporterMetricReader(PrometheusAspNetCoreOptions options)
{
+#pragma warning disable CA2000 // Dispose objects before losing scope
var exporter = new PrometheusExporter(options.ExporterOptions);
+#pragma warning restore CA2000 // Dispose objects before losing scope
return new BaseExportingMetricReader(exporter)
{
diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs
index f91a93f66bb..863695b975f 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs
+++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs
@@ -74,7 +74,7 @@ public async Task InvokeAsync(HttpContext httpContext)
? "application/openmetrics-text; version=1.0.0; charset=utf-8"
: "text/plain; charset=utf-8; version=0.0.4";
- await response.Body.WriteAsync(dataView.Array!, 0, dataView.Count).ConfigureAwait(false);
+ await response.Body.WriteAsync(dataView.Array.AsMemory(0, dataView.Count)).ConfigureAwait(false);
}
else
{
diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusCollectionManager.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusCollectionManager.cs
index 1c74e36bcf8..ce4c5384485 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusCollectionManager.cs
+++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusCollectionManager.cs
@@ -34,8 +34,8 @@ public PrometheusCollectionManager(PrometheusExporter exporter)
this.exporter = exporter;
this.scrapeResponseCacheDurationMilliseconds = this.exporter.ScrapeResponseCacheDurationMilliseconds;
this.onCollectRef = this.OnCollect;
- this.metricsCache = new Dictionary();
- this.scopes = new HashSet();
+ this.metricsCache = [];
+ this.scopes = [];
}
#if NET
@@ -68,10 +68,7 @@ public Task EnterCollect(bool openMetricsRequested)
// If a collection is already running, return a task to wait on the result.
if (this.collectionRunning)
{
- if (this.collectionTcs == null)
- {
- this.collectionTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
- }
+ this.collectionTcs ??= new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
Interlocked.Increment(ref this.readerCount);
this.ExitGlobalLock();
@@ -148,6 +145,22 @@ public void ExitCollect()
Interlocked.Decrement(ref this.readerCount);
}
+ private static bool IncreaseBufferSize(ref byte[] buffer)
+ {
+ var newBufferSize = buffer.Length * 2;
+
+ if (newBufferSize > 100 * 1024 * 1024)
+ {
+ return false;
+ }
+
+ var newBuffer = new byte[newBufferSize];
+ buffer.CopyTo(newBuffer, 0);
+ buffer = newBuffer;
+
+ return true;
+ }
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void EnterGlobalLock()
{
@@ -230,7 +243,7 @@ private ExportResult OnCollect(in Batch metrics)
}
catch (IndexOutOfRangeException)
{
- if (!this.IncreaseBufferSize(ref buffer))
+ if (!IncreaseBufferSize(ref buffer))
{
// there are two cases we might run into the following condition:
// 1. we have many metrics to be exported - in this case we probably want
@@ -268,7 +281,7 @@ private ExportResult OnCollect(in Batch metrics)
}
catch (IndexOutOfRangeException)
{
- if (!this.IncreaseBufferSize(ref buffer))
+ if (!IncreaseBufferSize(ref buffer))
{
throw;
}
@@ -285,7 +298,7 @@ private ExportResult OnCollect(in Batch metrics)
}
catch (IndexOutOfRangeException)
{
- if (!this.IncreaseBufferSize(ref buffer))
+ if (!IncreaseBufferSize(ref buffer))
{
throw;
}
@@ -307,11 +320,11 @@ private ExportResult OnCollect(in Batch metrics)
{
if (this.exporter.OpenMetricsRequested)
{
- this.previousOpenMetricsDataView = new ArraySegment(Array.Empty(), 0, 0);
+ this.previousOpenMetricsDataView = new ArraySegment([], 0, 0);
}
else
{
- this.previousPlainTextDataView = new ArraySegment(Array.Empty(), 0, 0);
+ this.previousPlainTextDataView = new ArraySegment([], 0, 0);
}
return ExportResult.Failure;
@@ -332,7 +345,7 @@ private int WriteTargetInfo(ref byte[] buffer)
}
catch (IndexOutOfRangeException)
{
- if (!this.IncreaseBufferSize(ref buffer))
+ if (!IncreaseBufferSize(ref buffer))
{
throw;
}
@@ -343,22 +356,6 @@ private int WriteTargetInfo(ref byte[] buffer)
return this.targetInfoBufferLength;
}
- private bool IncreaseBufferSize(ref byte[] buffer)
- {
- var newBufferSize = buffer.Length * 2;
-
- if (newBufferSize > 100 * 1024 * 1024)
- {
- return false;
- }
-
- var newBuffer = new byte[newBufferSize];
- buffer.CopyTo(newBuffer, 0);
- buffer = newBuffer;
-
- return true;
- }
-
private PrometheusMetric GetPrometheusMetric(Metric metric)
{
// Optimize writing metrics with bounded cache that has pre-calculated Prometheus names.
diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusMetric.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusMetric.cs
index cc9176ea0c5..9f80d6dc5d3 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusMetric.cs
+++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusMetric.cs
@@ -16,10 +16,10 @@ Histogram becomes histogram
UpDownCounter becomes gauge
* https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/data-model.md#otlp-metric-points-to-prometheus
*/
- private static readonly PrometheusType[] MetricTypes = new PrometheusType[]
- {
+ private static readonly PrometheusType[] MetricTypes =
+ [
PrometheusType.Untyped, PrometheusType.Counter, PrometheusType.Gauge, PrometheusType.Summary, PrometheusType.Histogram, PrometheusType.Histogram, PrometheusType.Histogram, PrometheusType.Histogram, PrometheusType.Gauge,
- };
+ ];
public PrometheusMetric(string name, string unit, PrometheusType type, bool disableTotalNameSuffixForCounters)
{
@@ -40,7 +40,7 @@ public PrometheusMetric(string name, string unit, PrometheusType type, bool disa
// [OpenMetrics UNIT metadata](https://github.com/prometheus/OpenMetrics/blob/v1.0.0/specification/OpenMetrics.md#metricfamily)
// and as a suffix to the metric name. The unit suffix comes before any type-specific suffixes.
// https://github.com/open-telemetry/opentelemetry-specification/blob/3dfb383fe583e3b74a2365c5a1d90256b273ee76/specification/compatibility/prometheus_and_openmetrics.md#metric-metadata-1
- if (!sanitizedName.EndsWith(sanitizedUnit))
+ if (!sanitizedName.EndsWith(sanitizedUnit, StringComparison.Ordinal))
{
sanitizedName += $"_{sanitizedUnit}";
openMetricsName += $"_{sanitizedUnit}";
@@ -51,14 +51,14 @@ public PrometheusMetric(string name, string unit, PrometheusType type, bool disa
// Exporters SHOULD provide a configuration option to disable the addition of `_total` suffixes.
// https://github.com/open-telemetry/opentelemetry-specification/blob/b2f923fb1650dde1f061507908b834035506a796/specification/compatibility/prometheus_and_openmetrics.md#L286
// Note that we no longer append '_ratio' for units that are '1', see: https://github.com/open-telemetry/opentelemetry-specification/issues/4058
- if (type == PrometheusType.Counter && !sanitizedName.EndsWith("_total") && !disableTotalNameSuffixForCounters)
+ if (type == PrometheusType.Counter && !sanitizedName.EndsWith("_total", StringComparison.Ordinal) && !disableTotalNameSuffixForCounters)
{
sanitizedName += "_total";
}
// For counters requested using OpenMetrics format, the MetricFamily name MUST be suffixed with '_total', regardless of the setting to disable the 'total' suffix.
// https://github.com/prometheus/OpenMetrics/blob/v1.0.0/specification/OpenMetrics.md#counter-1
- if (type == PrometheusType.Counter && !openMetricsName.EndsWith("_total"))
+ if (type == PrometheusType.Counter && !openMetricsName.EndsWith("_total", StringComparison.Ordinal))
{
openMetricsName += "_total";
}
@@ -127,7 +127,7 @@ internal static string SanitizeMetricName(string metricName)
return sb?.ToString() ?? metricName;
- static StringBuilder CreateStringBuilder(string name) => new StringBuilder(name.Length);
+ static StringBuilder CreateStringBuilder(string name) => new(name.Length);
}
internal static string RemoveAnnotations(string unit)
@@ -179,7 +179,7 @@ internal static string RemoveAnnotations(string unit)
private static string SanitizeOpenMetricsName(string metricName)
{
- if (metricName.EndsWith("_total"))
+ if (metricName.EndsWith("_total", StringComparison.Ordinal))
{
return metricName.Substring(0, metricName.Length - 6);
}
diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializer.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializer.cs
index 54cbfac4170..c199a6695c5 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializer.cs
+++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializer.cs
@@ -17,8 +17,6 @@ internal static partial class PrometheusSerializer
{
#pragma warning disable SA1310 // Field name should not contain an underscore
private const byte ASCII_QUOTATION_MARK = 0x22; // '"'
- private const byte ASCII_FULL_STOP = 0x2E; // '.'
- private const byte ASCII_HYPHEN_MINUS = 0x2D; // '-'
private const byte ASCII_REVERSE_SOLIDUS = 0x5C; // '\\'
private const byte ASCII_LINEFEED = 0x0A; // `\n`
#pragma warning restore SA1310 // Field name should not contain an underscore
diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/OpenTelemetry.Exporter.Prometheus.HttpListener.csproj b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/OpenTelemetry.Exporter.Prometheus.HttpListener.csproj
index 4e087919be2..a886b62ed65 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/OpenTelemetry.Exporter.Prometheus.HttpListener.csproj
+++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/OpenTelemetry.Exporter.Prometheus.HttpListener.csproj
@@ -5,6 +5,7 @@
Stand-alone HttpListener for hosting OpenTelemetry .NET Prometheus Exporter
$(PackageTags);prometheus;metrics
coreunstable-
+ latest-all
diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs
index cecda73f7c9..b3bdf286f34 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs
+++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs
@@ -30,12 +30,20 @@ public PrometheusHttpListener(PrometheusExporter exporter, PrometheusHttpListene
string path = options.ScrapeEndpointPath ?? PrometheusHttpListenerOptions.DefaultScrapeEndpointPath;
- if (!path.StartsWith("/"))
+#if NET
+ if (!path.StartsWith('/'))
+#else
+ if (!path.StartsWith("/", StringComparison.Ordinal))
+#endif
{
path = $"/{path}";
}
- if (!path.EndsWith("/"))
+#if NET
+ if (!path.EndsWith('/'))
+#else
+ if (!path.EndsWith("/", StringComparison.Ordinal))
+#endif
{
path = $"{path}/";
}
@@ -164,7 +172,11 @@ private async Task ProcessRequestAsync(HttpListenerContext context)
? "application/openmetrics-text; version=1.0.0; charset=utf-8"
: "text/plain; charset=utf-8; version=0.0.4";
- await context.Response.OutputStream.WriteAsync(dataView.Array!, 0, dataView.Count).ConfigureAwait(false);
+#if NET
+ await context.Response.OutputStream.WriteAsync(dataView.Array.AsMemory(0, dataView.Count)).ConfigureAwait(false);
+#else
+ await context.Response.OutputStream.WriteAsync(dataView.Array, 0, dataView.Count).ConfigureAwait(false);
+#endif
}
else
{
diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerMeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerMeterProviderBuilderExtensions.cs
index 7289432cdcf..94eea0f5742 100644
--- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerMeterProviderBuilderExtensions.cs
+++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerMeterProviderBuilderExtensions.cs
@@ -62,7 +62,7 @@ public static MeterProviderBuilder AddPrometheusHttpListener(
});
}
- private static MetricReader BuildPrometheusHttpListenerMetricReader(
+ private static BaseExportingMetricReader BuildPrometheusHttpListenerMetricReader(
PrometheusHttpListenerOptions options)
{
var exporter = new PrometheusExporter(new PrometheusExporterOptions
@@ -78,8 +78,10 @@ private static MetricReader BuildPrometheusHttpListenerMetricReader(
try
{
+#pragma warning disable CA2000 // Dispose objects before losing scope
var listener = new PrometheusHttpListener(exporter, options);
- exporter.OnDispose = () => listener.Dispose();
+#pragma warning restore CA2000 // Dispose objects before losing scope
+ exporter.OnDispose = listener.Dispose;
listener.Start();
}
catch (Exception ex)
diff --git a/src/OpenTelemetry/Metrics/Reader/BaseExportingMetricReader.cs b/src/OpenTelemetry/Metrics/Reader/BaseExportingMetricReader.cs
index 80f96cc143a..eeaa3fc68c5 100644
--- a/src/OpenTelemetry/Metrics/Reader/BaseExportingMetricReader.cs
+++ b/src/OpenTelemetry/Metrics/Reader/BaseExportingMetricReader.cs
@@ -17,7 +17,6 @@ public class BaseExportingMetricReader : MetricReader
///
protected readonly BaseExporter exporter;
- private readonly ExportModes supportedExportModes = ExportModes.Push | ExportModes.Pull;
private readonly string exportCalledMessage;
private readonly string exportSucceededMessage;
private readonly string exportFailedMessage;
@@ -38,12 +37,12 @@ public BaseExportingMetricReader(BaseExporter exporter)
if (attributes.Length > 0)
{
var attr = (ExportModesAttribute)attributes[attributes.Length - 1];
- this.supportedExportModes = attr.Supported;
+ this.SupportedExportModes = attr.Supported;
}
if (exporter is IPullMetricExporter pullExporter)
{
- if (this.supportedExportModes.HasFlag(ExportModes.Push))
+ if (this.SupportedExportModes.HasFlag(ExportModes.Push))
{
pullExporter.Collect = this.Collect;
}
@@ -69,7 +68,7 @@ public BaseExportingMetricReader(BaseExporter exporter)
///
/// Gets the supported .
///
- protected ExportModes SupportedExportModes => this.supportedExportModes;
+ protected ExportModes SupportedExportModes { get; } = ExportModes.Push | ExportModes.Pull;
internal override void SetParentProvider(BaseProvider parentProvider)
{
@@ -106,12 +105,12 @@ internal override bool ProcessMetrics(in Batch metrics, int timeoutMilli
///
protected override bool OnCollect(int timeoutMilliseconds)
{
- if (this.supportedExportModes.HasFlag(ExportModes.Push))
+ if (this.SupportedExportModes.HasFlag(ExportModes.Push))
{
return base.OnCollect(timeoutMilliseconds);
}
- if (this.supportedExportModes.HasFlag(ExportModes.Pull) && PullMetricScope.IsPullAllowed)
+ if (this.SupportedExportModes.HasFlag(ExportModes.Pull) && PullMetricScope.IsPullAllowed)
{
return base.OnCollect(timeoutMilliseconds);
}
diff --git a/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests.csproj b/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests.csproj
index 6c4ea8cb626..8c37feb0e25 100644
--- a/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests.csproj
+++ b/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests.csproj
@@ -4,6 +4,7 @@
Unit test project for Prometheus Exporter AspNetCore for OpenTelemetry
$(TargetFrameworksForAspNetCoreTests)
$(DefineConstants);PROMETHEUS_ASPNETCORE
+ latest-all
@@ -28,7 +29,7 @@
-
+
diff --git a/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusExporterMiddlewareTests.cs b/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusExporterMiddlewareTests.cs
index c34dba29582..98d503e8e92 100644
--- a/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusExporterMiddlewareTests.cs
+++ b/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusExporterMiddlewareTests.cs
@@ -3,6 +3,7 @@
#if !NETFRAMEWORK
using System.Diagnostics.Metrics;
+using System.Globalization;
using System.Net;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Builder;
@@ -112,7 +113,7 @@ public Task PrometheusExporterMiddlewareIntegration_MixedPredicateAndPath()
{
if (!rsp.Headers.TryGetValues("X-MiddlewareExecuted", out IEnumerable? headers))
{
- headers = Array.Empty();
+ headers = [];
}
Assert.Equal("true", headers.FirstOrDefault());
@@ -139,7 +140,7 @@ public Task PrometheusExporterMiddlewareIntegration_MixedPath()
{
if (!rsp.Headers.TryGetValues("X-MiddlewareExecuted", out IEnumerable? headers))
{
- headers = Array.Empty();
+ headers = [];
}
Assert.Equal("true", headers.FirstOrDefault());
@@ -314,7 +315,7 @@ public async Task PrometheusExporterMiddlewareIntegration_TestBufferSizeIncrease
using var client = host.GetTestClient();
- using var response = await client.GetAsync("/metrics");
+ using var response = await client.GetAsync(new Uri("/metrics", UriKind.Relative));
var text = await response.Content.ReadAsStringAsync();
Assert.NotEmpty(text);
@@ -372,7 +373,7 @@ private static async Task RunPrometheusExporterMiddlewareIntegrationTest(
string acceptHeader = "application/openmetrics-text",
KeyValuePair[]? meterTags = null)
{
- var requestOpenMetrics = acceptHeader.StartsWith("application/openmetrics-text");
+ var requestOpenMetrics = acceptHeader.StartsWith("application/openmetrics-text", StringComparison.Ordinal);
using var host = await StartTestHostAsync(configure, configureServices, registerMeterProvider, configureOptions);
@@ -400,7 +401,7 @@ private static async Task RunPrometheusExporterMiddlewareIntegrationTest(
client.DefaultRequestHeaders.Add("Accept", acceptHeader);
}
- using var response = await client.GetAsync(path);
+ using var response = await client.GetAsync(new Uri(path, UriKind.Relative));
var endTimestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds();
@@ -432,7 +433,7 @@ private static async Task VerifyAsync(long beginTimestamp, long endTimestamp, Ht
Assert.Equal("text/plain; charset=utf-8; version=0.0.4", response.Content.Headers.ContentType!.ToString());
}
- var additionalTags = meterTags != null && meterTags.Any()
+ var additionalTags = meterTags is { Length: > 0 }
? $"{string.Join(",", meterTags.Select(x => $"{x.Key}=\"{x.Value}\""))},"
: string.Empty;
@@ -464,7 +465,7 @@ private static async Task VerifyAsync(long beginTimestamp, long endTimestamp, Ht
Assert.True(matches.Count == 1, content);
- var timestamp = long.Parse(matches[0].Groups[1].Value.Replace(".", string.Empty));
+ var timestamp = long.Parse(matches[0].Groups[1].Value.Replace(".", string.Empty, StringComparison.Ordinal), CultureInfo.InvariantCulture);
Assert.True(beginTimestamp <= timestamp && timestamp <= endTimestamp, $"{beginTimestamp} {timestamp} {endTimestamp}");
}
diff --git a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/EventSourceTest.cs b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/EventSourceTests.cs
similarity index 92%
rename from test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/EventSourceTest.cs
rename to test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/EventSourceTests.cs
index baf8dc43377..b1aed407d63 100644
--- a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/EventSourceTest.cs
+++ b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/EventSourceTests.cs
@@ -6,7 +6,7 @@
namespace OpenTelemetry.Exporter.Prometheus.Tests;
-public class EventSourceTest
+public class EventSourceTests
{
[Fact]
public void EventSourceTest_PrometheusExporterEventSource()
diff --git a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests.csproj b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests.csproj
index 6d6c38ff489..cc044afe37f 100644
--- a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests.csproj
+++ b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests.csproj
@@ -4,9 +4,10 @@
Unit test project for Prometheus Exporter HttpListener for OpenTelemetry
$(TargetFrameworksForTests)
$(DefineConstants);PROMETHEUS_HTTP_LISTENER
+ latest-all
-
+
diff --git a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusCollectionManagerTests.cs b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusCollectionManagerTests.cs
index 36f5e124e67..75e3261b71a 100644
--- a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusCollectionManagerTests.cs
+++ b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusCollectionManagerTests.cs
@@ -31,7 +31,9 @@ public async Task EnterExitCollectTest(int scrapeResponseCacheDurationMillisecon
#endif
.Build())
{
+#pragma warning disable CA2000 // Dispose objects before losing scope
if (!provider.TryFindExporter(out PrometheusExporter? exporter))
+#pragma warning restore CA2000 // Dispose objects before losing scope
{
throw new InvalidOperationException("PrometheusExporter could not be found on MeterProvider.");
}
@@ -60,7 +62,7 @@ public async Task EnterExitCollectTest(int scrapeResponseCacheDurationMillisecon
return new Response
{
CollectionResponse = response,
- ViewPayload = openMetricsRequested ? response.OpenMetricsView.ToArray() : response.PlainTextView.ToArray(),
+ ViewPayload = openMetricsRequested ? [.. response.OpenMetricsView] : [.. response.PlainTextView],
};
}
finally
@@ -110,7 +112,10 @@ public async Task EnterExitCollectTest(int scrapeResponseCacheDurationMillisecon
exporter.CollectionManager.ExitCollect();
}
+#pragma warning disable CA1849 // 'Thread.Sleep(int)' synchronously blocks. Use await instead.
+ // Changing to await Task.Delay leads to test instability.
Thread.Sleep(exporter.ScrapeResponseCacheDurationMilliseconds);
+#pragma warning restore CA1849 // 'Thread.Sleep(int)' synchronously blocks. Use await instead.
counter.Add(100);
@@ -118,13 +123,13 @@ public async Task EnterExitCollectTest(int scrapeResponseCacheDurationMillisecon
{
collectTasks[i] = Task.Run(async () =>
{
- var response = await exporter.CollectionManager.EnterCollect(openMetricsRequested);
+ var collectionResponse = await exporter.CollectionManager.EnterCollect(openMetricsRequested);
try
{
return new Response
{
- CollectionResponse = response,
- ViewPayload = openMetricsRequested ? response.OpenMetricsView.ToArray() : response.PlainTextView.ToArray(),
+ CollectionResponse = collectionResponse,
+ ViewPayload = openMetricsRequested ? [.. collectionResponse.OpenMetricsView] : [.. collectionResponse.PlainTextView],
};
}
finally
@@ -152,7 +157,7 @@ public async Task EnterExitCollectTest(int scrapeResponseCacheDurationMillisecon
}
}
- private class Response
+ private sealed class Response
{
public PrometheusCollectionManager.CollectionResponse CollectionResponse;
diff --git a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHttpListenerTests.cs b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHttpListenerTests.cs
index 0ac04d2f299..7ff58940692 100644
--- a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHttpListenerTests.cs
+++ b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHttpListenerTests.cs
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics.Metrics;
+using System.Globalization;
using System.Net;
#if NETFRAMEWORK
using System.Net.Http;
@@ -47,7 +48,7 @@ public void UriPrefixesEmptyList()
{
Assert.Throws(() =>
{
- TestPrometheusHttpListenerUriPrefixOptions(new string[] { });
+ TestPrometheusHttpListenerUriPrefixOptions([]);
});
}
@@ -63,25 +64,25 @@ public void UriPrefixesInvalid()
[Fact]
public async Task PrometheusExporterHttpServerIntegration()
{
- await this.RunPrometheusExporterHttpServerIntegrationTest();
+ await RunPrometheusExporterHttpServerIntegrationTest();
}
[Fact]
public async Task PrometheusExporterHttpServerIntegration_NoMetrics()
{
- await this.RunPrometheusExporterHttpServerIntegrationTest(skipMetrics: true);
+ await RunPrometheusExporterHttpServerIntegrationTest(skipMetrics: true);
}
[Fact]
public async Task PrometheusExporterHttpServerIntegration_NoOpenMetrics()
{
- await this.RunPrometheusExporterHttpServerIntegrationTest(acceptHeader: string.Empty);
+ await RunPrometheusExporterHttpServerIntegrationTest(acceptHeader: string.Empty);
}
[Fact]
public async Task PrometheusExporterHttpServerIntegration_UseOpenMetricsVersionHeader()
{
- await this.RunPrometheusExporterHttpServerIntegrationTest(acceptHeader: "application/openmetrics-text; version=1.0.0");
+ await RunPrometheusExporterHttpServerIntegrationTest(acceptHeader: "application/openmetrics-text; version=1.0.0");
}
[Fact]
@@ -93,7 +94,7 @@ public async Task PrometheusExporterHttpServerIntegration_NoOpenMetrics_WithMete
new("meter2", "value2"),
};
- await this.RunPrometheusExporterHttpServerIntegrationTest(acceptHeader: string.Empty, meterTags: tags);
+ await RunPrometheusExporterHttpServerIntegrationTest(acceptHeader: string.Empty, meterTags: tags);
}
[Fact]
@@ -105,7 +106,7 @@ public async Task PrometheusExporterHttpServerIntegration_OpenMetrics_WithMeterT
new("meter2", "value2"),
};
- await this.RunPrometheusExporterHttpServerIntegrationTest(acceptHeader: "application/openmetrics-text; version=1.0.0", meterTags: tags);
+ await RunPrometheusExporterHttpServerIntegrationTest(acceptHeader: "application/openmetrics-text; version=1.0.0", meterTags: tags);
}
[Fact]
@@ -113,7 +114,6 @@ public void PrometheusHttpListenerThrowsOnStart()
{
Random random = new Random();
int retryAttempts = 5;
- int port = 0;
string? address = null;
PrometheusExporter? exporter = null;
@@ -122,7 +122,9 @@ public void PrometheusHttpListenerThrowsOnStart()
// Step 1: Start a listener on a random port.
while (retryAttempts-- != 0)
{
- port = random.Next(2000, 5000);
+#pragma warning disable CA5394 // Do not use insecure randomness
+ int port = random.Next(2000, 5000);
+#pragma warning restore CA5394 // Do not use insecure randomness
address = $"http://localhost:{port}/";
try
@@ -179,7 +181,7 @@ public async Task PrometheusExporterHttpServerIntegration_TestBufferSizeIncrease
var oneKb = new string('A', 1024);
for (var x = 0; x < 8500; x++)
{
- attributes.Add(new KeyValuePair(x.ToString(), oneKb));
+ attributes.Add(new KeyValuePair(x.ToString(CultureInfo.InvariantCulture), oneKb));
}
var provider = BuildMeterProvider(meter, attributes, out var address);
@@ -197,11 +199,11 @@ public async Task PrometheusExporterHttpServerIntegration_TestBufferSizeIncrease
client.DefaultRequestHeaders.Add("Accept", acceptHeader);
}
- using var response = await client.GetAsync($"{address}metrics");
+ using var response = await client.GetAsync(new Uri($"{address}metrics"));
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var content = await response.Content.ReadAsStringAsync();
- Assert.Contains("counter_double_999", content);
+ Assert.Contains("counter_double_999", content, StringComparison.Ordinal);
Assert.DoesNotContain('\0', content);
provider.Dispose();
@@ -222,13 +224,14 @@ private static MeterProvider BuildMeterProvider(Meter meter, IEnumerable[]? meterTags = null)
+ private static async Task RunPrometheusExporterHttpServerIntegrationTest(bool skipMetrics = false, string acceptHeader = "application/openmetrics-text", KeyValuePair[]? meterTags = null)
{
- var requestOpenMetrics = acceptHeader.StartsWith("application/openmetrics-text");
+ var requestOpenMetrics = acceptHeader.StartsWith("application/openmetrics-text", StringComparison.Ordinal);
using var meter = new Meter(MeterName, MeterVersion, meterTags);
@@ -288,7 +286,7 @@ private async Task RunPrometheusExporterHttpServerIntegrationTest(bool skipMetri
client.DefaultRequestHeaders.Add("Accept", acceptHeader);
}
- using var response = await client.GetAsync($"{address}metrics");
+ using var response = await client.GetAsync(new Uri($"{address}metrics"));
if (!skipMetrics)
{
@@ -304,7 +302,7 @@ private async Task RunPrometheusExporterHttpServerIntegrationTest(bool skipMetri
Assert.Equal("text/plain; charset=utf-8; version=0.0.4", response.Content.Headers.ContentType!.ToString());
}
- var additionalTags = meterTags != null && meterTags.Any()
+ var additionalTags = meterTags is { Length: > 0 }
? $"{string.Join(",", meterTags.Select(x => $"{x.Key}='{x.Value}'"))},"
: string.Empty;
diff --git a/test/OpenTelemetry.Tests/Logs/LogRecordSharedPoolTests.cs b/test/OpenTelemetry.Tests/Logs/LogRecordSharedPoolTests.cs
index d38c82d1a0c..3da599ad2b9 100644
--- a/test/OpenTelemetry.Tests/Logs/LogRecordSharedPoolTests.cs
+++ b/test/OpenTelemetry.Tests/Logs/LogRecordSharedPoolTests.cs
@@ -170,7 +170,7 @@ public async Task ExportTest(bool warmup)
using BatchLogRecordExportProcessor processor = new(new NoopExporter());
- List tasks = new();
+ List tasks = [];
for (int i = 0; i < Environment.ProcessorCount; i++)
{
@@ -230,7 +230,7 @@ public async Task DeadlockTest()
var pool = LogRecordSharedPool.Current;
- List tasks = new();
+ List tasks = [];
for (int i = 0; i < Environment.ProcessorCount; i++)
{
diff --git a/test/OpenTelemetry.Tests/Shared/EventSourceTestHelper.cs b/test/OpenTelemetry.Tests/Shared/EventSourceTestHelper.cs
index d7066c3195c..8b30f7694b1 100644
--- a/test/OpenTelemetry.Tests/Shared/EventSourceTestHelper.cs
+++ b/test/OpenTelemetry.Tests/Shared/EventSourceTestHelper.cs
@@ -4,6 +4,7 @@
using System.Diagnostics.Tracing;
using System.Globalization;
using System.Reflection;
+using Xunit.Sdk;
namespace OpenTelemetry.Tests;
@@ -34,11 +35,11 @@ private static void VerifyMethodImplementation(EventSource eventSource, MethodIn
actualEvent = listener.Messages.FirstOrDefault(x => x.EventId == 0);
if (actualEvent != null)
{
- throw new Exception(actualEvent.Message);
+ throw new InvalidOperationException(actualEvent.Message);
}
// give up
- throw new Exception("Listener failed to collect event.");
+ throw new InvalidOperationException("Listener failed to collect event.");
}
VerifyEventId(eventMethod, actualEvent);
@@ -49,7 +50,7 @@ private static void VerifyMethodImplementation(EventSource eventSource, MethodIn
{
var name = eventMethod.DeclaringType?.Name + "." + eventMethod.Name;
- throw new Exception("Method '" + name + "' is implemented incorrectly.", e);
+ throw new InvalidOperationException("Method '" + name + "' is implemented incorrectly.", e);
}
finally
{
@@ -116,7 +117,7 @@ private static void AssertEqual(string methodName, T expected, T actual)
methodName,
expected,
actual);
- throw new Exception(errorMessage);
+ throw EqualException.ForMismatchedValuesWithError(expected, actual, banner: errorMessage);
}
}
@@ -128,6 +129,6 @@ private static EventAttribute GetEventAttribute(MethodInfo eventMethod)
private static IEnumerable GetEventMethods(EventSource eventSource)
{
MethodInfo[] methods = eventSource.GetType().GetMethods();
- return methods.Where(m => m.GetCustomAttributes(typeof(EventAttribute), false).Any());
+ return methods.Where(m => m.GetCustomAttributes(typeof(EventAttribute), false).Length > 0);
}
}
diff --git a/test/OpenTelemetry.Tests/Shared/TestEventListener.cs b/test/OpenTelemetry.Tests/Shared/TestEventListener.cs
index fb497190f5e..572ce1a6c4b 100644
--- a/test/OpenTelemetry.Tests/Shared/TestEventListener.cs
+++ b/test/OpenTelemetry.Tests/Shared/TestEventListener.cs
@@ -8,7 +8,7 @@ namespace OpenTelemetry.Tests;
///
/// Event listener for testing event sources.
///
-internal class TestEventListener : EventListener
+internal sealed class TestEventListener : EventListener
{
/// Unique Id used to identify events from the test thread.
private readonly Guid activityId;
@@ -66,6 +66,12 @@ public void ClearMessages()
this.events.Clear();
}
+ public override void Dispose()
+ {
+ this.eventWritten.Dispose();
+ base.Dispose();
+ }
+
/// Handler for event source writes.
/// The event data that was written.
protected override void OnEventWritten(EventWrittenEventArgs eventData)
diff --git a/test/OpenTelemetry.Tests/Shared/Utils.cs b/test/OpenTelemetry.Tests/Shared/Utils.cs
index d85c8c74e47..95f24821d0e 100644
--- a/test/OpenTelemetry.Tests/Shared/Utils.cs
+++ b/test/OpenTelemetry.Tests/Shared/Utils.cs
@@ -6,7 +6,7 @@
namespace OpenTelemetry.Tests;
-internal class Utils
+internal static class Utils
{
[MethodImpl(MethodImplOptions.NoInlining)]
public static string GetCurrentMethodName()