diff --git a/src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.RequestTelemetryLogger.cs b/src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.RequestTelemetryLogger.cs
index 8cf7606e93faf..cce10a8aebd40 100644
--- a/src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.RequestTelemetryLogger.cs
+++ b/src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.RequestTelemetryLogger.cs
@@ -4,8 +4,6 @@
using System;
using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
using System.Threading;
using Microsoft.CodeAnalysis.Internal.Log;
@@ -17,7 +15,7 @@ internal partial class RequestExecutionQueue
/// Logs metadata on LSP requests (duration, success / failure metrics)
/// for this particular LSP server instance.
///
- internal class RequestTelemetryLogger : IDisposable
+ internal sealed class RequestTelemetryLogger : IDisposable
{
private const string QueuedDurationKey = "QueuedDuration";
@@ -26,7 +24,7 @@ internal class RequestTelemetryLogger : IDisposable
///
/// Histogram to aggregate the time in queue metrics.
///
- private HistogramLogAggregator? _queuedDurationLogAggregator;
+ private readonly HistogramLogAggregator _queuedDurationLogAggregator;
///
/// Histogram to aggregate total request duration metrics.
@@ -36,7 +34,7 @@ internal class RequestTelemetryLogger : IDisposable
/// This provides highly detailed buckets when duration is in MS, but less detailed
/// when the duration is in terms of seconds or minutes.
///
- private HistogramLogAggregator? _requestDurationLogAggregator;
+ private readonly HistogramLogAggregator _requestDurationLogAggregator;
///
/// Store request counters in a concurrent dictionary as non-mutating LSP requests can
@@ -46,6 +44,8 @@ internal class RequestTelemetryLogger : IDisposable
private readonly LogAggregator _findDocumentResults;
+ private int _disposed;
+
public RequestTelemetryLogger(string serverTypeName)
{
_serverTypeName = serverTypeName;
@@ -79,10 +79,10 @@ public void UpdateTelemetryData(
{
// Find the bucket corresponding to the queued duration and update the count of durations in that bucket.
// This is not broken down per method as time in queue is not specific to an LSP method.
- _queuedDurationLogAggregator?.IncreaseCount(QueuedDurationKey, Convert.ToDecimal(queuedDuration.TotalMilliseconds));
+ _queuedDurationLogAggregator.IncreaseCount(QueuedDurationKey, Convert.ToDecimal(queuedDuration.TotalMilliseconds));
// Store the request time metrics per LSP method.
- _requestDurationLogAggregator?.IncreaseCount(methodName, Convert.ToDecimal(ComputeLogValue(requestDuration.TotalMilliseconds)));
+ _requestDurationLogAggregator.IncreaseCount(methodName, Convert.ToDecimal(ComputeLogValue(requestDuration.TotalMilliseconds)));
_requestCounters.GetOrAdd(methodName, (_) => new Counter()).IncrementCount(result);
}
@@ -103,8 +103,12 @@ private static double ComputeLogValue(double durationInMS)
///
public void Dispose()
{
- if (_queuedDurationLogAggregator is null || _queuedDurationLogAggregator.IsEmpty
- || _requestDurationLogAggregator is null || _requestDurationLogAggregator.IsEmpty)
+ if (Interlocked.Exchange(ref _disposed, 1) != 0)
+ {
+ return;
+ }
+
+ if (_queuedDurationLogAggregator.IsEmpty || _requestDurationLogAggregator.IsEmpty)
{
return;
}
@@ -150,10 +154,7 @@ public void Dispose()
}
}));
- // Clear telemetry we've published in case dispose is called multiple times.
_requestCounters.Clear();
- _queuedDurationLogAggregator = null;
- _requestDurationLogAggregator = null;
}
private class Counter