MetricsEventSource
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
namespace System.Diagnostics.Metrics
{
[EventSource(Name = "System.Diagnostics.Metrics")]
internal sealed class MetricsEventSource : EventSource
{
public static class Keywords
{
public const EventKeywords Messages = (EventKeywords)1;
public const EventKeywords TimeSeriesValues = (EventKeywords)2;
public const EventKeywords InstrumentPublishing = (EventKeywords)4;
}
private sealed class CommandHandler
{
private AggregationManager _aggregationManager;
private string _sessionId = "";
private static readonly char[] s_instrumentSeparators = new char[4] {
'\r',
'\n',
',',
';'
};
public MetricsEventSource Parent { get; set; }
public CommandHandler(MetricsEventSource parent)
{
Parent = parent;
}
public void OnEventCommand(EventCommandEventArgs command)
{
try {
if (OperatingSystem.IsBrowser())
Parent.Error("", "System.Diagnostics.Metrics EventSource not supported on browser");
else {
if (command.Command != 0 && command.Command != EventCommand.Disable && command.Command != EventCommand.Enable)
goto IL_00b7;
if (_aggregationManager == null)
goto IL_00ac;
if (command.Command != EventCommand.Enable && command.Command != 0) {
_aggregationManager.Dispose();
_aggregationManager = null;
Parent.Message("Previous session with id " + _sessionId + " is stopped");
goto IL_00ac;
}
Parent.MultipleSessionsNotSupportedError(_sessionId);
}
goto end_IL_000d;
IL_00b7:
if ((command.Command == EventCommand.Update || command.Command == EventCommand.Enable) && command.Arguments != null) {
if (command.Arguments.TryGetValue("SessionId", out string value)) {
_sessionId = value;
Parent.Message("SessionId argument received: " + _sessionId);
} else {
_sessionId = Guid.NewGuid().ToString();
Parent.Message("New session started. SessionId auto-generated: " + _sessionId);
}
double num = 1;
double result;
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler;
if (command.Arguments.TryGetValue("RefreshInterval", out string value2)) {
Parent.Message("RefreshInterval argument received: " + value2);
if (!double.TryParse(value2, out result)) {
MetricsEventSource parent = Parent;
defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(49, 1);
defaultInterpolatedStringHandler.AppendLiteral("Failed to parse RefreshInterval. Using default ");
defaultInterpolatedStringHandler.AppendFormatted(num);
defaultInterpolatedStringHandler.AppendLiteral("s.");
parent.Message(defaultInterpolatedStringHandler.ToStringAndClear());
result = num;
} else if (result < 0.1) {
MetricsEventSource parent2 = Parent;
defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(59, 1);
defaultInterpolatedStringHandler.AppendLiteral("RefreshInterval too small. Using minimum interval ");
defaultInterpolatedStringHandler.AppendFormatted(0.1);
defaultInterpolatedStringHandler.AppendLiteral(" seconds.");
parent2.Message(defaultInterpolatedStringHandler.ToStringAndClear());
result = 0.1;
}
} else {
MetricsEventSource parent3 = Parent;
defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(54, 1);
defaultInterpolatedStringHandler.AppendLiteral("No RefreshInterval argument received. Using default ");
defaultInterpolatedStringHandler.AppendFormatted(num);
defaultInterpolatedStringHandler.AppendLiteral("s.");
parent3.Message(defaultInterpolatedStringHandler.ToStringAndClear());
result = num;
}
int num2 = 1000;
int result2;
if (command.Arguments.TryGetValue("MaxTimeSeries", out string value3)) {
Parent.Message("MaxTimeSeries argument received: " + value3);
if (!int.TryParse(value3, out result2)) {
MetricsEventSource parent4 = Parent;
defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(45, 1);
defaultInterpolatedStringHandler.AppendLiteral("Failed to parse MaxTimeSeries. Using default ");
defaultInterpolatedStringHandler.AppendFormatted(num2);
parent4.Message(defaultInterpolatedStringHandler.ToStringAndClear());
result2 = num2;
}
} else {
MetricsEventSource parent5 = Parent;
defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(50, 1);
defaultInterpolatedStringHandler.AppendLiteral("No MaxTimeSeries argument received. Using default ");
defaultInterpolatedStringHandler.AppendFormatted(num2);
parent5.Message(defaultInterpolatedStringHandler.ToStringAndClear());
result2 = num2;
}
int num3 = 20;
int result3;
if (command.Arguments.TryGetValue("MaxHistograms", out string value4)) {
Parent.Message("MaxHistograms argument received: " + value4);
if (!int.TryParse(value4, out result3)) {
MetricsEventSource parent6 = Parent;
defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(45, 1);
defaultInterpolatedStringHandler.AppendLiteral("Failed to parse MaxHistograms. Using default ");
defaultInterpolatedStringHandler.AppendFormatted(num3);
parent6.Message(defaultInterpolatedStringHandler.ToStringAndClear());
result3 = num3;
}
} else {
MetricsEventSource parent7 = Parent;
defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(49, 1);
defaultInterpolatedStringHandler.AppendLiteral("No MaxHistogram argument received. Using default ");
defaultInterpolatedStringHandler.AppendFormatted(num3);
parent7.Message(defaultInterpolatedStringHandler.ToStringAndClear());
result3 = num3;
}
string sessionId = _sessionId;
_aggregationManager = new AggregationManager(result2, result3, delegate(Instrument i, LabeledAggregationStatistics s) {
TransmitMetricValue(i, s, sessionId);
}, delegate(DateTime startIntervalTime, DateTime endIntervalTime) {
Parent.CollectionStart(sessionId, startIntervalTime, endIntervalTime);
}, delegate(DateTime startIntervalTime, DateTime endIntervalTime) {
Parent.CollectionStop(sessionId, startIntervalTime, endIntervalTime);
}, delegate(Instrument i) {
Parent.BeginInstrumentReporting(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description);
}, delegate(Instrument i) {
Parent.EndInstrumentReporting(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description);
}, delegate(Instrument i) {
Parent.InstrumentPublished(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description);
}, delegate {
Parent.InitialInstrumentEnumerationComplete(sessionId);
}, delegate(Exception e) {
Parent.Error(sessionId, e.ToString());
}, delegate {
Parent.TimeSeriesLimitReached(sessionId);
}, delegate {
Parent.HistogramLimitReached(sessionId);
}, delegate(Exception e) {
Parent.ObservableInstrumentCallbackError(sessionId, e.ToString());
});
_aggregationManager.SetCollectionPeriod(TimeSpan.FromSeconds(result));
if (command.Arguments.TryGetValue("Metrics", out string value5)) {
Parent.Message("Metrics argument received: " + value5);
ParseSpecs(value5);
} else
Parent.Message("No Metrics argument received");
_aggregationManager.Start();
}
goto end_IL_000d;
IL_00ac:
_sessionId = "";
goto IL_00b7;
end_IL_000d:;
} catch (Exception e2) when (LogError(e2)) {
}
}
private bool LogError(Exception e)
{
Parent.Error(_sessionId, e.ToString());
return false;
}
[UnsupportedOSPlatform("browser")]
private void ParseSpecs(string metricsSpecs)
{
if (metricsSpecs != null) {
string[] array = metricsSpecs.Split(s_instrumentSeparators, StringSplitOptions.RemoveEmptyEntries);
string[] array2 = array;
foreach (string text in array2) {
MetricSpec metricSpec = MetricSpec.Parse(text);
MetricsEventSource parent = Parent;
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(15, 1);
defaultInterpolatedStringHandler.AppendLiteral("Parsed metric: ");
defaultInterpolatedStringHandler.AppendFormatted(metricSpec);
parent.Message(defaultInterpolatedStringHandler.ToStringAndClear());
if (metricSpec.InstrumentName != null)
_aggregationManager.Include(metricSpec.MeterName, metricSpec.InstrumentName);
else
_aggregationManager.Include(metricSpec.MeterName);
}
}
}
private static void TransmitMetricValue(Instrument instrument, LabeledAggregationStatistics stats, string sessionId)
{
RateStatistics rateStatistics = stats.AggregationStatistics as RateStatistics;
double value;
if (rateStatistics != null) {
if (rateStatistics.IsMonotonic) {
MetricsEventSource log = Log;
string name = instrument.Meter.Name;
string version = instrument.Meter.Version;
string name2 = instrument.Name;
string unit = instrument.Unit;
string tags = FormatTags(stats.Labels);
object rate;
if (!rateStatistics.Delta.HasValue)
rate = "";
else {
value = rateStatistics.Delta.Value;
rate = value.ToString(CultureInfo.InvariantCulture);
}
log.CounterRateValuePublished(sessionId, name, version, name2, unit, tags, (string)rate);
} else {
MetricsEventSource log2 = Log;
string name3 = instrument.Meter.Name;
string version2 = instrument.Meter.Version;
string name4 = instrument.Name;
string unit2 = instrument.Unit;
string tags2 = FormatTags(stats.Labels);
object rate2;
if (!rateStatistics.Delta.HasValue)
rate2 = "";
else {
value = rateStatistics.Delta.Value;
rate2 = value.ToString(CultureInfo.InvariantCulture);
}
log2.UpDownCounterRateValuePublished(sessionId, name3, version2, name4, unit2, tags2, (string)rate2);
}
} else {
LastValueStatistics lastValueStatistics = stats.AggregationStatistics as LastValueStatistics;
if (lastValueStatistics != null) {
MetricsEventSource log3 = Log;
string name5 = instrument.Meter.Name;
string version3 = instrument.Meter.Version;
string name6 = instrument.Name;
string unit3 = instrument.Unit;
string tags3 = FormatTags(stats.Labels);
object lastValue;
if (!lastValueStatistics.LastValue.HasValue)
lastValue = "";
else {
value = lastValueStatistics.LastValue.Value;
lastValue = value.ToString(CultureInfo.InvariantCulture);
}
log3.GaugeValuePublished(sessionId, name5, version3, name6, unit3, tags3, (string)lastValue);
} else {
HistogramStatistics histogramStatistics = stats.AggregationStatistics as HistogramStatistics;
if (histogramStatistics != null)
Log.HistogramValuePublished(sessionId, instrument.Meter.Name, instrument.Meter.Version, instrument.Name, instrument.Unit, FormatTags(stats.Labels), FormatQuantiles(histogramStatistics.Quantiles));
}
}
}
private static string FormatTags(KeyValuePair<string, string>[] labels)
{
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < labels.Length; i++) {
stringBuilder.Append(labels[i].Key).Append('=').Append(labels[i].Value);
if (i != labels.Length - 1)
stringBuilder.Append(',');
}
return stringBuilder.ToString();
}
private static string FormatQuantiles(QuantileValue[] quantiles)
{
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < quantiles.Length; i++) {
stringBuilder.Append(quantiles[i].Quantile).Append('=').Append(quantiles[i].Value);
if (i != quantiles.Length - 1)
stringBuilder.Append(';');
}
return stringBuilder.ToString();
}
}
private sealed class MetricSpec
{
public string MeterName { get; set; }
public string InstrumentName { get; set; }
public MetricSpec(string meterName, string instrumentName)
{
MeterName = meterName;
InstrumentName = instrumentName;
}
public static MetricSpec Parse(string text)
{
int num = text.IndexOf('\\');
if (num < 0)
return new MetricSpec(text.Trim(), null);
ReadOnlySpan<char> readOnlySpan = text.AsSpan(0, num).Trim();
string meterName = readOnlySpan.ToString();
readOnlySpan = text.AsSpan(num + 1).Trim();
string instrumentName = readOnlySpan.ToString();
return new MetricSpec(meterName, instrumentName);
}
public override string ToString()
{
if (InstrumentName == null)
return MeterName;
return MeterName + "\\" + InstrumentName;
}
}
public static readonly MetricsEventSource Log = new MetricsEventSource();
private CommandHandler _handler;
private CommandHandler Handler {
get {
if (_handler == null)
Interlocked.CompareExchange(ref _handler, new CommandHandler(this), null);
return _handler;
}
}
private MetricsEventSource()
{
}
[Event(1, Keywords = (EventKeywords)1)]
public void Message(string Message)
{
WriteEvent(1, Message);
}
[Event(2, Keywords = (EventKeywords)2)]
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")]
public void CollectionStart(string sessionId, DateTime intervalStartTime, DateTime intervalEndTime)
{
WriteEvent(2, new object[3] {
sessionId,
intervalStartTime,
intervalEndTime
});
}
[Event(3, Keywords = (EventKeywords)2)]
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")]
public void CollectionStop(string sessionId, DateTime intervalStartTime, DateTime intervalEndTime)
{
WriteEvent(3, new object[3] {
sessionId,
intervalStartTime,
intervalEndTime
});
}
[Event(4, Keywords = (EventKeywords)2)]
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")]
public void CounterRateValuePublished(string sessionId, string meterName, string meterVersion, string instrumentName, string unit, string tags, string rate)
{
WriteEvent(4, new object[7] {
sessionId,
meterName,
meterVersion ?? "",
instrumentName,
unit ?? "",
tags,
rate
});
}
[Event(5, Keywords = (EventKeywords)2)]
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")]
public void GaugeValuePublished(string sessionId, string meterName, string meterVersion, string instrumentName, string unit, string tags, string lastValue)
{
WriteEvent(5, new object[7] {
sessionId,
meterName,
meterVersion ?? "",
instrumentName,
unit ?? "",
tags,
lastValue
});
}
[Event(6, Keywords = (EventKeywords)2)]
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")]
public void HistogramValuePublished(string sessionId, string meterName, string meterVersion, string instrumentName, string unit, string tags, string quantiles)
{
WriteEvent(6, new object[7] {
sessionId,
meterName,
meterVersion ?? "",
instrumentName,
unit ?? "",
tags,
quantiles
});
}
[Event(7, Keywords = (EventKeywords)2)]
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")]
public void BeginInstrumentReporting(string sessionId, string meterName, string meterVersion, string instrumentName, string instrumentType, string unit, string description)
{
WriteEvent(7, new object[7] {
sessionId,
meterName,
meterVersion ?? "",
instrumentName,
instrumentType,
unit ?? "",
description ?? ""
});
}
[Event(8, Keywords = (EventKeywords)2)]
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")]
public void EndInstrumentReporting(string sessionId, string meterName, string meterVersion, string instrumentName, string instrumentType, string unit, string description)
{
WriteEvent(8, new object[7] {
sessionId,
meterName,
meterVersion ?? "",
instrumentName,
instrumentType,
unit ?? "",
description ?? ""
});
}
[Event(9, Keywords = (EventKeywords)7)]
public void Error(string sessionId, string errorMessage)
{
WriteEvent(9, sessionId, errorMessage);
}
[Event(10, Keywords = (EventKeywords)6)]
public void InitialInstrumentEnumerationComplete(string sessionId)
{
WriteEvent(10, sessionId);
}
[Event(11, Keywords = (EventKeywords)4)]
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")]
public void InstrumentPublished(string sessionId, string meterName, string meterVersion, string instrumentName, string instrumentType, string unit, string description)
{
WriteEvent(11, new object[7] {
sessionId,
meterName,
meterVersion ?? "",
instrumentName,
instrumentType,
unit ?? "",
description ?? ""
});
}
[Event(12, Keywords = (EventKeywords)2)]
public void TimeSeriesLimitReached(string sessionId)
{
WriteEvent(12, sessionId);
}
[Event(13, Keywords = (EventKeywords)2)]
public void HistogramLimitReached(string sessionId)
{
WriteEvent(13, sessionId);
}
[Event(14, Keywords = (EventKeywords)2)]
public void ObservableInstrumentCallbackError(string sessionId, string errorMessage)
{
WriteEvent(14, sessionId, errorMessage);
}
[Event(15, Keywords = (EventKeywords)7)]
public void MultipleSessionsNotSupportedError(string runningSessionId)
{
WriteEvent(15, runningSessionId);
}
[Event(16, Keywords = (EventKeywords)2)]
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")]
public void UpDownCounterRateValuePublished(string sessionId, string meterName, string meterVersion, string instrumentName, string unit, string tags, string rate)
{
WriteEvent(16, new object[7] {
sessionId,
meterName,
meterVersion ?? "",
instrumentName,
unit ?? "",
tags,
rate
});
}
[NonEvent]
protected override void OnEventCommand(EventCommandEventArgs command)
{
lock (this) {
Handler.OnEventCommand(command);
}
}
}
}