Avoid race condition in DiagnosticCounter (dotnet/coreclr#26260)
[mono-project.git] / netcore / System.Private.CoreLib / shared / System / Diagnostics / Tracing / IncrementingEventCounter.cs
blob1fd66cd1a9e0b02547c51bc4757e0667309d5c63
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 #if ES_BUILD_STANDALONE
6 using System;
7 using System.Diagnostics;
8 #endif
10 #if ES_BUILD_STANDALONE
11 namespace Microsoft.Diagnostics.Tracing
12 #else
13 namespace System.Diagnostics.Tracing
14 #endif
16 /// <summary>
17 /// IncrementingEventCounter is a variant of EventCounter for variables that are ever-increasing.
18 /// Ex) # of exceptions in the runtime.
19 /// It does not calculate statistics like mean, standard deviation, etc. because it only accumulates
20 /// the counter value.
21 /// </summary>
22 public partial class IncrementingEventCounter : DiagnosticCounter
24 /// <summary>
25 /// Initializes a new instance of the <see cref="IncrementingEventCounter"/> class.
26 /// IncrementingEventCounter live as long as the EventSource that they are attached to unless they are
27 /// explicitly Disposed.
28 /// </summary>
29 /// <param name="name">The name.</param>
30 /// <param name="eventSource">The event source.</param>
31 public IncrementingEventCounter(string name, EventSource eventSource) : base(name, eventSource)
33 Publish();
36 /// <summary>
37 /// Writes 'value' to the stream of values tracked by the counter. This updates the sum and other statistics that will
38 /// be logged on the next timer interval.
39 /// </summary>
40 /// <param name="increment">The value to increment by.</param>
41 public void Increment(double increment = 1)
43 lock (this)
45 _increment += increment;
49 public TimeSpan DisplayRateTimeScale { get; set; }
50 private double _increment;
51 private double _prevIncrement;
53 public override string ToString() => $"IncrementingEventCounter '{Name}' Increment {_increment}";
55 internal override void WritePayload(float intervalSec, int pollingIntervalMillisec)
57 lock (this) // Lock the counter
59 IncrementingCounterPayload payload = new IncrementingCounterPayload();
60 payload.Name = Name;
61 payload.IntervalSec = intervalSec;
62 payload.DisplayName = DisplayName ?? "";
63 payload.DisplayRateTimeScale = (DisplayRateTimeScale == TimeSpan.Zero) ? "" : DisplayRateTimeScale.ToString("c");
64 payload.Series = $"Interval={pollingIntervalMillisec}"; // TODO: This may need to change when we support multi-session
65 payload.CounterType = "Sum";
66 payload.Metadata = GetMetadataString();
67 payload.Increment = _increment - _prevIncrement;
68 payload.DisplayUnits = DisplayUnits ?? "";
69 _prevIncrement = _increment;
70 EventSource.Write("EventCounters", new EventSourceOptions() { Level = EventLevel.LogAlways }, new IncrementingEventCounterPayloadType(payload));
74 // Updates the value.
75 internal void UpdateMetric()
77 lock (this)
79 _prevIncrement = _increment;
85 /// <summary>
86 /// This is the payload that is sent in the with EventSource.Write
87 /// </summary>
88 [EventData]
89 internal class IncrementingEventCounterPayloadType
91 public IncrementingEventCounterPayloadType(IncrementingCounterPayload payload) { Payload = payload; }
92 public IncrementingCounterPayload Payload { get; set; }