Skip to content

feat: add TagList overload to Metrics-Emit APIs as Attributes parameter #5259

@Flash0ver

Description

@Flash0ver

Summary

Add overloads to Sentry.SentrySdk.Metrics.Emit* methods with a by-ref System.Diagnostics.TagList parameter for Sentry Attributes.

Remarks

Added in .NET 6.0, and via the out-of-band NuGet package System.Diagnostics.DiagnosticSource, the System.Diagnostics.TagList is a collection of KeyValuePair<string, object?> that stores up to 8 (eight) tags within this struct, and only allocates contiguous regions of memory on the heap when representing more than 8 (eight) tags (starting with an array of 16 elements, growing again by eight when exceeded).
The TagList is used widely across the System.Diagnostics.Metrics APIs.

We can provide an overload to the EmitCounter, EmitGauge and EmitDistribution method groups so that callers can make use of this type, too, by representing Sentry Attributes.

A common scenario is when collecting/exporting Meter-based Metrics via the System.Diagnostics.Metrics.MeterListener, that we are currently prototyping.

We should pass this struct ByRef rather than ByVal, as it's a larger struct. Preferred in a readonly fashion, where in might be the best fit (because an rvalue also makes sense semantically since we don't necessarily require a location). But make sure to only invoke readonly members of that struct, as it's not a readonly struct.

Also, consume via a for loop rather than a foreach loop, because the implicit GetEnumerator implementation does not return the struct-based TagList.Enumerator, but just the IEnumerator<KeyValuePair<string, object?>> interface, which is allocating a box for the struct on the heap on runtimes that cannot de-virtualize the call via dynamic PGO.
See blog Performance Improvements in .NET 10.

Potential follow-up

Propose to dotnet/runtime to expose the internal Tags property, returning ReadOnlySpan<KeyValuePair<string, object?>>, via an unsafe Marshal type, similar to System.Runtime.InteropServices.AsSpan<>(System.Collections.Generic.List<T>?), highlighting our usage example where we could forward to our already existing internal KeyValuePair<string, object> overloads, rather than providing a whole new code path for in TagList.

Metadata

Metadata

Assignees

Labels

.NETPull requests that update .net codeImprovementMetricsPerformancepublic APIAdditions/modifications to, or removals from, the public API surface area.
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions