<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="8.0.0-preview.1.23110.8" />

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); } } } }