-
-
Notifications
You must be signed in to change notification settings - Fork 205
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Automatic Tags and Span Aggregates for Metrics (#3191)
- Loading branch information
1 parent
0edfe93
commit 448b2e2
Showing
17 changed files
with
520 additions
and
126 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
namespace Sentry.Internal.Extensions; | ||
|
||
internal static class DictionaryExtensions | ||
{ | ||
public static void AddIfNotNullOrEmpty<TKey>(this IDictionary<TKey, string> dictionary, TKey key, string? value) | ||
where TKey : notnull | ||
{ | ||
if (!string.IsNullOrEmpty(value)) | ||
{ | ||
dictionary.Add(key, value); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
using Sentry.Protocol.Metrics; | ||
|
||
namespace Sentry; | ||
|
||
internal class MetricsSummaryAggregator | ||
{ | ||
private Lazy<ConcurrentDictionary<string, SpanMetric>> LazyMeasurements { get; } = new(); | ||
internal ConcurrentDictionary<string, SpanMetric> Measurements => LazyMeasurements.Value; | ||
|
||
public void Add( | ||
MetricType ty, | ||
string key, | ||
double value = 1.0, | ||
MeasurementUnit? unit = null, | ||
IDictionary<string, string>? tags = null | ||
) | ||
{ | ||
unit ??= MeasurementUnit.None; | ||
|
||
var bucketKey = MetricHelper.GetMetricBucketKey(ty, key, unit.Value, tags); | ||
|
||
Measurements.AddOrUpdate( | ||
bucketKey, | ||
_ => new SpanMetric(ty, key, value, unit.Value, tags), | ||
(_, metric) => | ||
{ | ||
// This prevents multiple threads from trying to mutate the metric at the same time. The only other | ||
// operation performed against metrics is adding one to the bucket (guaranteed to be atomic due to | ||
// the use of a ConcurrentDictionary for the timeBucket). | ||
lock (metric) | ||
{ | ||
metric.Add(value); | ||
} | ||
return metric; | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
using Sentry.Extensibility; | ||
|
||
namespace Sentry.Protocol.Metrics; | ||
|
||
internal class MetricsSummary : ISentryJsonSerializable | ||
{ | ||
private readonly IDictionary<string, List<SpanMetric>> _measurements; | ||
|
||
public MetricsSummary(MetricsSummaryAggregator aggregator) | ||
{ | ||
// For the Metrics Summary we group all the metrics by an export key. | ||
// See https://github.com/getsentry/rfcs/blob/main/text/0123-metrics-correlation.md#basics | ||
var measurements = new Dictionary<string, List<SpanMetric>>(); | ||
foreach (var (_, value) in aggregator.Measurements) | ||
{ | ||
var exportKey = value.ExportKey; | ||
#if NET6_0_OR_GREATER | ||
measurements.TryAdd(exportKey, new List<SpanMetric>()); | ||
#else | ||
if (!measurements.ContainsKey(exportKey)) | ||
{ | ||
measurements.Add(exportKey, new List<SpanMetric>()); | ||
} | ||
#endif | ||
measurements[exportKey].Add(value); | ||
} | ||
_measurements = measurements.ToImmutableSortedDictionary(); | ||
} | ||
|
||
public void WriteTo(Utf8JsonWriter writer, IDiagnosticLogger? logger) | ||
{ | ||
writer.WriteStartObject(); | ||
|
||
foreach (var (exportKey, value) in _measurements) | ||
{ | ||
writer.WritePropertyName(exportKey); | ||
writer.WriteStartArray(); | ||
foreach (var metric in value.OrderBy(x => MetricHelper.GetMetricBucketKey(x.MetricType, x.Key, x.Unit, x.Tags))) | ||
{ | ||
metric.WriteTo(writer, logger); | ||
} | ||
writer.WriteEndArray(); | ||
} | ||
|
||
writer.WriteEndObject(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
using Sentry.Extensibility; | ||
using Sentry.Internal.Extensions; | ||
|
||
namespace Sentry.Protocol.Metrics; | ||
|
||
internal record SpanMetric | ||
{ | ||
public SpanMetric(MetricType MetricType, | ||
string key, | ||
double value, | ||
MeasurementUnit unit, | ||
IDictionary<string, string>? tags = null) | ||
{ | ||
this.MetricType = MetricType; | ||
Key = key; | ||
Unit = unit; | ||
Tags = tags; | ||
Min = value; | ||
Max = value; | ||
Sum = value; | ||
} | ||
|
||
public MetricType MetricType { get; init; } | ||
public string Key { get; init; } | ||
public MeasurementUnit Unit { get; init; } | ||
public IDictionary<string, string>? Tags { get; init; } | ||
|
||
public double Min { get; private set; } | ||
public double Max { get; private set; } | ||
public double Sum { get; private set; } | ||
public double Count { get; private set; } = 1; | ||
|
||
public string ExportKey => $"{MetricType.ToStatsdType()}:{Key}@{Unit}"; | ||
|
||
public void Add(double value) | ||
{ | ||
Min = Math.Min(Min, value); | ||
Max = Math.Max(Max, value); | ||
Sum += value; | ||
Count++; | ||
} | ||
|
||
/// <inheritdoc cref="ISentryJsonSerializable.WriteTo"/> | ||
public void WriteTo(Utf8JsonWriter writer, IDiagnosticLogger? logger) | ||
{ | ||
writer.WriteStartObject(); | ||
writer.WriteNumber("min", Min); | ||
writer.WriteNumber("max", Max); | ||
writer.WriteNumber("count", Count); | ||
writer.WriteNumber("sum", Sum); | ||
writer.WriteStringDictionaryIfNotEmpty("tags", (IEnumerable<KeyValuePair<string, string?>>?)Tags); | ||
writer.WriteEndObject(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.