-
-
Notifications
You must be signed in to change notification settings - Fork 212
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Added basic metric types * Moved Metric classes * Added Increment aggregator * Implemented Gauge metric * Implemented Distribution and Set aggregations * Added Metrics to ISentryClient API * Update Hub.cs * Verify tests * Basic flush loop (no tests yet) * Implemented statsd serialization * Update CHANGELOG.md * Split tests for Aggregagtor and BucketHelper * Update MetricBucketHelperTests.cs * Integrated review feedback * Create MetricTests.verify.cs * Updated verify tests * Added Timing * Added a (commented out) test to check if the aggregator is threadsafe * Fixed concurrency issue (could still make this more performant) * Reduced the scope of the lock for updating metrics * Fixed unit tests * Update MetricAggregator.cs * Initial implementation of Code Locations * Update Program.cs * Updated solution filters * Update CHANGELOG.md * Changed Flush to FlushAsync * Metrics now get flushed properly when disposing of the Hub * Fixed serialization for code locations * Update Timing.cs * Clear stale seen periods at the end of each day * Update CodeLocations.cs * Fixed stacklevel when calling one of the two Timing constructors * Removed IAsyncDisposable from MetricAggregator * Cherry picked getsentry/Ben.Demystifier#4 * Update Ben.Demystifier * Get line numbers with stack traces without enhanced stack traces * Update Ben.Demystifier * Reversed changes to AspNetCore.Basic sample (unrelated to this PR) * Update Program.cs * Improved the lock when incrementing/adding to existing metrics * Tweaking docs * Update CHANGELOG.md Co-authored-by: Bruno Garcia <[email protected]> * Integrating review feedback * Source generated RegEx in metric helper * Update Envelope.cs * Review feedback * Integrating review feedback * More performant string delimited tags used in the bucket key * Integrating review feedback * Integrated review feedback * Removed unused private field --------- Co-authored-by: Bruno Garcia <[email protected]>
- Loading branch information
1 parent
8e298f8
commit 0fde2e3
Showing
51 changed files
with
1,982 additions
and
7 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
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
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,107 @@ | ||
using System.Numerics; | ||
|
||
namespace Sentry.Samples.Console.Metrics; | ||
|
||
internal static class Program | ||
{ | ||
private static readonly Random Roll = new(); | ||
|
||
private static void Main() | ||
{ | ||
// Enable the SDK | ||
using (SentrySdk.Init(options => | ||
{ | ||
options.Dsn = | ||
// NOTE: ADD YOUR OWN DSN BELOW so you can see the events in your own Sentry account | ||
"https://[email protected]/5428537"; | ||
|
||
options.Debug = true; | ||
options.StackTraceMode = StackTraceMode.Enhanced; | ||
// Initialize some (non null) ExperimentalMetricsOptions to enable Sentry Metrics, | ||
options.ExperimentalMetrics = new ExperimentalMetricsOptions | ||
{ | ||
EnableCodeLocations = | ||
true // Set this to false if you don't want to track code locations for some reason | ||
}; | ||
})) | ||
{ | ||
System.Console.WriteLine("Measure, Yeah, Measure!"); | ||
while (true) | ||
{ | ||
// Perform your task here | ||
switch (Roll.Next(1,3)) | ||
{ | ||
case 1: | ||
PlaySetBingo(10); | ||
break; | ||
case 2: | ||
CreateRevenueGauge(100); | ||
break; | ||
case 3: | ||
MeasureShrimp(30); | ||
break; | ||
} | ||
|
||
|
||
// Optional: Delay to prevent tight looping | ||
var sleepTime = Roll.Next(1, 10); | ||
System.Console.WriteLine($"Sleeping for {sleepTime} second(s)."); | ||
System.Console.WriteLine("Press any key to stop..."); | ||
Thread.Sleep(TimeSpan.FromSeconds(sleepTime)); | ||
// Check if a key has been pressed | ||
if (System.Console.KeyAvailable) | ||
{ | ||
break; | ||
} | ||
} | ||
System.Console.WriteLine("Measure up"); | ||
} | ||
} | ||
|
||
private static void PlaySetBingo(int attempts) | ||
{ | ||
var solution = new[] { 3, 5, 7, 11, 13, 17 }; | ||
|
||
// The Timing class creates a distribution that is designed to measure the amount of time it takes to run code | ||
// blocks. By default it will use a unit of Seconds - we're configuring it to use milliseconds here though. | ||
using (new Timing("bingo", MeasurementUnit.Duration.Millisecond)) | ||
{ | ||
for (var i = 0; i < attempts; i++) | ||
{ | ||
var guess = Roll.Next(1, 100); | ||
// This demonstrates the use of a set metric. | ||
SentrySdk.Metrics.Gauge("guesses", guess); | ||
|
||
// And this is a counter | ||
SentrySdk.Metrics.Increment(solution.Contains(guess) ? "correct_answers" : "incorrect_answers"); | ||
} | ||
} | ||
} | ||
|
||
private static void CreateRevenueGauge(int sampleCount) | ||
{ | ||
using (new Timing(nameof(CreateRevenueGauge), MeasurementUnit.Duration.Millisecond)) | ||
{ | ||
for (var i = 0; i < sampleCount; i++) | ||
{ | ||
var movement = Roll.NextDouble() * 30 - Roll.NextDouble() * 10; | ||
// This demonstrates measuring something in your app using a gauge... we're also using a custom | ||
// measurement unit here (which is optional - by default the unit will be "None") | ||
SentrySdk.Metrics.Gauge("revenue", movement, MeasurementUnit.Custom("$")); | ||
} | ||
} | ||
} | ||
|
||
private static void MeasureShrimp(int sampleCount) | ||
{ | ||
using (new Timing(nameof(MeasureShrimp), MeasurementUnit.Duration.Millisecond)) | ||
{ | ||
for (var i = 0; i < sampleCount; i++) | ||
{ | ||
var sizeOfShrimp = 15 + Roll.NextDouble() * 30; | ||
// This is an example of emitting a distribution metric | ||
SentrySdk.Metrics.Distribution("shrimp.size", sizeOfShrimp, MeasurementUnit.Custom("cm")); | ||
} | ||
} | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
samples/Sentry.Samples.Console.Metrics/Sentry.Samples.Console.Metrics.csproj
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,12 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net8.0</TargetFramework> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\..\src\Sentry\Sentry.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
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,50 @@ | ||
namespace Sentry; | ||
|
||
internal class DisabledMetricAggregator : IMetricAggregator | ||
{ | ||
public void Increment(string key, double value = 1.0, MeasurementUnit? unit = null, | ||
IDictionary<string, string>? tags = null, | ||
DateTimeOffset? timestamp = null, int stackLevel = 1) | ||
{ | ||
// No Op | ||
} | ||
|
||
public void Gauge(string key, double value = 1.0, MeasurementUnit? unit = null, | ||
IDictionary<string, string>? tags = null, | ||
DateTimeOffset? timestamp = null, int stackLevel = 1) | ||
{ | ||
// No Op | ||
} | ||
|
||
public void Distribution(string key, double value = 1.0, MeasurementUnit? unit = null, | ||
IDictionary<string, string>? tags = null, | ||
DateTimeOffset? timestamp = null, int stackLevel = 1) | ||
{ | ||
// No Op | ||
} | ||
|
||
public void Set(string key, int value, MeasurementUnit? unit = null, | ||
IDictionary<string, string>? tags = null, | ||
DateTimeOffset? timestamp = null, int stackLevel = 1) | ||
{ | ||
// No Op | ||
} | ||
|
||
public void Timing(string key, double value, MeasurementUnit.Duration unit = MeasurementUnit.Duration.Second, | ||
IDictionary<string, string>? tags = null, | ||
DateTimeOffset? timestamp = null, int stackLevel = 1) | ||
{ | ||
// No Op | ||
} | ||
|
||
public Task FlushAsync(bool force = true, CancellationToken cancellationToken = default) | ||
{ | ||
// No Op | ||
return Task.CompletedTask; | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
// No Op | ||
} | ||
} |
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,107 @@ | ||
namespace Sentry; | ||
|
||
/// <summary> | ||
/// Exposes EXPERIMENTAL capability to emit metrics. This API is subject to change without major version bumps so use | ||
/// with caution. We advise disabling in production at the moment. | ||
/// </summary> | ||
public interface IMetricAggregator: IDisposable | ||
{ | ||
/// <summary> | ||
/// Emits a Counter metric | ||
/// </summary> | ||
/// <param name="key">A unique key identifying the metric</param> | ||
/// <param name="value">The value to be added</param> | ||
/// <param name="unit">An optional <see cref="MeasurementUnit"/></param> | ||
/// <param name="tags">Optional Tags to associate with the metric</param> | ||
/// <param name="timestamp"> | ||
/// The time when the metric was emitted. Defaults to the time at which the metric is emitted, if no value is provided. | ||
/// </param> | ||
/// <param name="stackLevel">Optional number of stacks levels to ignore when determining the code location</param> | ||
void Increment(string key, | ||
double value = 1.0, | ||
MeasurementUnit? unit = null, | ||
IDictionary<string, string>? tags = null, | ||
DateTimeOffset? timestamp = null, | ||
int stackLevel = 1); | ||
|
||
/// <summary> | ||
/// Emits a Gauge metric | ||
/// </summary> | ||
/// <param name="key">A unique key identifying the metric</param> | ||
/// <param name="value">The value to be added</param> | ||
/// <param name="unit">An optional <see cref="MeasurementUnit"/></param> | ||
/// <param name="tags">Optional Tags to associate with the metric</param> | ||
/// <param name="timestamp"> | ||
/// The time when the metric was emitted. Defaults to the time at which the metric is emitted, if no value is provided. | ||
/// </param> | ||
/// <param name="stackLevel">Optional number of stacks levels to ignore when determining the code location</param> | ||
void Gauge(string key, | ||
double value = 1.0, | ||
MeasurementUnit? unit = null, | ||
IDictionary<string, string>? tags = null, | ||
DateTimeOffset? timestamp = null, | ||
int stackLevel = 1); | ||
|
||
/// <summary> | ||
/// Emits a Distribution metric | ||
/// </summary> | ||
/// <param name="key">A unique key identifying the metric</param> | ||
/// <param name="value">The value to be added</param> | ||
/// <param name="unit">An optional <see cref="MeasurementUnit"/></param> | ||
/// <param name="tags">Optional Tags to associate with the metric</param> | ||
/// <param name="timestamp"> | ||
/// The time when the metric was emitted. Defaults to the time at which the metric is emitted, if no value is provided. | ||
/// </param> | ||
/// <param name="stackLevel">Optional number of stacks levels to ignore when determining the code location</param> | ||
void Distribution(string key, | ||
double value = 1.0, | ||
MeasurementUnit? unit = null, | ||
IDictionary<string, string>? tags = null, | ||
DateTimeOffset? timestamp = null, | ||
int stackLevel = 1); | ||
|
||
/// <summary> | ||
/// Emits a Set metric | ||
/// </summary> | ||
/// <param name="key">A unique key identifying the metric</param> | ||
/// <param name="value">The value to be added</param> | ||
/// <param name="unit">An optional <see cref="MeasurementUnit"/></param> | ||
/// <param name="tags">Optional Tags to associate with the metric</param> | ||
/// <param name="timestamp"> | ||
/// The time when the metric was emitted. Defaults to the time at which the metric is emitted, if no value is provided. | ||
/// </param> | ||
/// <param name="stackLevel">Optional number of stacks levels to ignore when determining the code location</param> | ||
void Set(string key, | ||
int value, | ||
MeasurementUnit? unit = null, | ||
IDictionary<string, string>? tags = null, | ||
DateTimeOffset? timestamp = null, | ||
int stackLevel = 1); | ||
|
||
/// <summary> | ||
/// Emits a distribution with the time it takes to run a given code block. | ||
/// </summary> | ||
/// <param name="key">A unique key identifying the metric</param> | ||
/// <param name="value">The value to be added</param> | ||
/// <param name="unit"> | ||
/// An optional <see cref="MeasurementUnit.Duration"/>. Defaults to <see cref="MeasurementUnit.Duration.Second"/> | ||
/// </param> | ||
/// <param name="tags">Optional Tags to associate with the metric</param> | ||
/// <param name="timestamp">The time when the metric was emitted</param> | ||
/// <param name="stackLevel">Optional number of stacks levels to ignore when determining the code location</param> | ||
void Timing(string key, | ||
double value, | ||
MeasurementUnit.Duration unit = MeasurementUnit.Duration.Second, | ||
IDictionary<string, string>? tags = null, | ||
DateTimeOffset? timestamp = null, | ||
int stackLevel = 1); | ||
|
||
/// <summary> | ||
/// Flushes any flushable metrics and/or code locations. | ||
/// If <paramref name="force"/> is true then the cutoff is ignored and all metrics are flushed. | ||
/// </summary> | ||
/// <param name="force">Forces all buckets to be flushed, ignoring the cutoff</param> | ||
/// <param name="cancellationToken">A <see cref="CancellationToken"/></param> | ||
/// <returns>False if a shutdown is requested during flush, true otherwise</returns> | ||
Task FlushAsync(bool force = true, CancellationToken cancellationToken = default); | ||
} |
Oops, something went wrong.