Skip to content

Commit

Permalink
Support Exposing new Metric properties using EventSource (#90417)
Browse files Browse the repository at this point in the history
  • Loading branch information
tarekgh authored Aug 11, 2023
1 parent 685b593 commit 13337d8
Show file tree
Hide file tree
Showing 3 changed files with 213 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ namespace System.Diagnostics.Metrics
// it may also not be a win to further pessimize the slow-path (JIT compilation is expensive) to squeeze yet more cycles out of
// the fast path.
// - Allocations per lookup: Any lookup of 3 or fewer labels on the above fast path is allocation free. We have separate
// dictionaries dependending on the number of labels in the list and the dictionary keys are structures representing fixed size
// dictionaries depending on the number of labels in the list and the dictionary keys are structures representing fixed size
// lists of strings or objects. For example with two labels the lookup is done in a
// FixedSizeLabelNameDictionary<StringSequence2, ConcurrentDictionary<ObjectSequence2, TAggregator>>
// Above 3 labels we have StringSequenceMany and ObjectSequenceMany which wraps an underlying string[] or object?[] respectively.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
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;
Expand Down Expand Up @@ -144,29 +145,51 @@ public void HistogramValuePublished(string sessionId, string meterName, string?
WriteEvent(6, sessionId, meterName, meterVersion ?? "", instrumentName, unit ?? "", tags, quantiles, count, sum);
}

// Sent when we begin to monitor the value of a intrument, either because new session filter arguments changed subscriptions
// Sent when we begin to monitor the value of a instrument, either because new session filter arguments changed subscriptions
// or because an instrument matching the pre-existing filter has just been created. This event precedes all *MetricPublished events
// for the same named instrument.
[Event(7, Keywords = Keywords.TimeSeriesValues)]
[Event(7, Keywords = Keywords.TimeSeriesValues, Version = 1)]
#if !NET8_0_OR_GREATER
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")]
#endif
public void BeginInstrumentReporting(string sessionId, string meterName, string? meterVersion, string instrumentName, string instrumentType, string? unit, string? description)
public void BeginInstrumentReporting(
string sessionId,
string meterName,
string? meterVersion,
string instrumentName,
string instrumentType,
string? unit,
string? description,
string instrumentTags,
string meterTags,
string meterScopeHash)
{
WriteEvent(7, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? "");
WriteEvent(7, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? "",
instrumentTags, meterTags, meterScopeHash);
}

// Sent when we stop monitoring the value of a intrument, either because new session filter arguments changed subscriptions
// Sent when we stop monitoring the value of a instrument, either because new session filter arguments changed subscriptions
// or because the Meter has been disposed.
[Event(8, Keywords = Keywords.TimeSeriesValues)]
[Event(8, Keywords = Keywords.TimeSeriesValues, Version = 1)]
#if !NET8_0_OR_GREATER
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")]
#endif
public void EndInstrumentReporting(string sessionId, string meterName, string? meterVersion, string instrumentName, string instrumentType, string? unit, string? description)
public void EndInstrumentReporting(
string sessionId,
string meterName,
string? meterVersion,
string instrumentName,
string instrumentType,
string? unit,
string? description,
string instrumentTags,
string meterTags,
string meterScopeHash)
{
WriteEvent(8, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? "");
WriteEvent(8, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? "",
instrumentTags, meterTags, meterScopeHash);
}

[Event(9, Keywords = Keywords.TimeSeriesValues | Keywords.Messages | Keywords.InstrumentPublishing)]
Expand All @@ -181,14 +204,25 @@ public void InitialInstrumentEnumerationComplete(string sessionId)
WriteEvent(10, sessionId);
}

[Event(11, Keywords = Keywords.InstrumentPublishing)]
[Event(11, Keywords = Keywords.InstrumentPublishing, Version = 1)]
#if !NET8_0_OR_GREATER
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")]
#endif
public void InstrumentPublished(string sessionId, string meterName, string? meterVersion, string instrumentName, string instrumentType, string? unit, string? description)
public void InstrumentPublished(
string sessionId,
string meterName,
string? meterVersion,
string instrumentName,
string instrumentType,
string? unit,
string? description,
string instrumentTags,
string meterTags,
string meterScopeHash)
{
WriteEvent(11, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? "");
WriteEvent(11, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? "",
instrumentTags, meterTags, meterScopeHash);
}

[Event(12, Keywords = Keywords.TimeSeriesValues)]
Expand Down Expand Up @@ -403,9 +437,12 @@ public void OnEventCommand(EventCommandEventArgs command)
(i, s) => TransmitMetricValue(i, s, sessionId),
(startIntervalTime, endIntervalTime) => Parent.CollectionStart(sessionId, startIntervalTime, endIntervalTime),
(startIntervalTime, endIntervalTime) => Parent.CollectionStop(sessionId, startIntervalTime, endIntervalTime),
i => Parent.BeginInstrumentReporting(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description),
i => Parent.EndInstrumentReporting(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description),
i => Parent.InstrumentPublished(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description),
i => Parent.BeginInstrumentReporting(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description,
FormatTags(i.Tags), FormatTags(i.Meter.Tags), FormatScopeHash(i.Meter.Scope)),
i => Parent.EndInstrumentReporting(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description,
FormatTags(i.Tags), FormatTags(i.Meter.Tags), FormatScopeHash(i.Meter.Scope)),
i => Parent.InstrumentPublished(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description,
FormatTags(i.Tags), FormatTags(i.Meter.Tags), FormatScopeHash(i.Meter.Scope)),
() => Parent.InitialInstrumentEnumerationComplete(sessionId),
e => Parent.Error(sessionId, e.ToString()),
() => Parent.TimeSeriesLimitReached(sessionId),
Expand Down Expand Up @@ -648,6 +685,39 @@ private static void TransmitMetricValue(Instrument instrument, LabeledAggregatio
}
}

private static string FormatScopeHash(object? scope) =>
scope is null ? string.Empty : RuntimeHelpers.GetHashCode(scope).ToString(CultureInfo.InvariantCulture);

private static string FormatTags(IEnumerable<KeyValuePair<string, object?>>? tags)
{
if (tags is null)
{
return string.Empty;
}

StringBuilder sb = new StringBuilder();
bool first = true;
foreach (KeyValuePair<string, object?> tag in tags)
{
if (first)
{
first = false;
}
else
{
sb.Append(',');
}

sb.Append(tag.Key).Append('=');

if (tag.Value is not null)
{
sb.Append(tag.Value.ToString());
}
}
return sb.ToString();
}

private static string FormatTags(KeyValuePair<string, string>[] labels)
{
StringBuilder sb = new StringBuilder();
Expand Down
Loading

0 comments on commit 13337d8

Please sign in to comment.