Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### Features

- GA release for Sentry Metrics ([#5023](https://github.com/getsentry/sentry-dotnet/pull/5023))

## 6.2.0

### Features
Expand Down
1 change: 0 additions & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

<!-- Ignore our own diagnostic ids - these are meant to be external warnings only -->
<NoWarn>$(NoWarn);SENTRY0001</NoWarn>
<NoWarn>$(NoWarn);SENTRYTRACECONNECTEDMETRICS</NoWarn> <!--https://github.com/getsentry/sentry-dotnet/discussions/4838-->

<!-- Allow references to unsigned assemblies (like MAUI) from signed projects -->
<NoWarn>$(NoWarn);CS8002</NoWarn>
Expand Down
10 changes: 5 additions & 5 deletions samples/Sentry.Samples.Console.Basic/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@
return log.Level is SentryLogLevel.Info ? null : log;
});

// Sentry (trace-connected) Metrics via SentrySdk.Experimental.Metrics are enabled by default.
options.Experimental.SetBeforeSendMetric(static metric =>
// Sentry (trace-connected) Metrics via SentrySdk.Metrics are enabled by default.
options.SetBeforeSendMetric(static metric =>
{
if (metric.TryGetValue(out int integer) && integer < 0)
{
Expand Down Expand Up @@ -104,13 +104,13 @@ async Task FirstFunction()
SentrySdk.Logger.LogInfo("HTTP Request completed.");

// Counter-Metric prevented from being sent to Sentry via "BeforeSendMetric" callback
SentrySdk.Experimental.Metrics.EmitCounter("sentry.samples.console.basic.ignore", -1);
SentrySdk.Metrics.EmitCounter("sentry.samples.console.basic.ignore", -1);

// Counter-Metric modified before sending it to Sentry via "BeforeSendMetric" callback
SentrySdk.Experimental.Metrics.EmitCounter("sentry.samples.console.basic.http_requests_completed", 1);
SentrySdk.Metrics.EmitCounter("sentry.samples.console.basic.http_requests_completed", 1);

// Distribution-Metric sent as is (see "BeforeSendMetric" callback)
SentrySdk.Experimental.Metrics.EmitDistribution("sentry.samples.console.basic.http_request_duration", stopwatch.Elapsed.TotalSeconds, MeasurementUnit.Duration.Second,
SentrySdk.Metrics.EmitDistribution("sentry.samples.console.basic.http_request_duration", stopwatch.Elapsed.TotalSeconds, MeasurementUnit.Duration.Second,
[new KeyValuePair<string, object>("http.request.method", HttpMethod.Get.Method), new KeyValuePair<string, object>("http.response.status_code", (int)HttpStatusCode.OK)]);
}

Expand Down
17 changes: 2 additions & 15 deletions src/Sentry/BindableSentryOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ internal partial class BindableSentryOptions
public string? Environment { get; set; }
public string? Dsn { get; set; }
public bool? EnableLogs { get; set; }
public bool? EnableMetrics { get; set; }
public int? MaxQueueItems { get; set; }
public int? MaxCacheItems { get; set; }
public TimeSpan? ShutdownTimeout { get; set; }
Expand Down Expand Up @@ -56,8 +57,6 @@ internal partial class BindableSentryOptions
public bool? EnableSpotlight { get; set; }
public string? SpotlightUrl { get; set; }

public ExperimentalSentryOptions? Experimental { get; set; }

public void ApplyTo(SentryOptions options)
{
options.IsGlobalModeEnabled = IsGlobalModeEnabled ?? options.IsGlobalModeEnabled;
Expand All @@ -75,6 +74,7 @@ public void ApplyTo(SentryOptions options)
options.Environment = Environment ?? options.Environment;
options.Dsn = Dsn ?? options.Dsn;
options.EnableLogs = EnableLogs ?? options.EnableLogs;
options.EnableMetrics = EnableMetrics ?? options.EnableMetrics;
options.MaxQueueItems = MaxQueueItems ?? options.MaxQueueItems;
options.MaxCacheItems = MaxCacheItems ?? options.MaxCacheItems;
options.ShutdownTimeout = ShutdownTimeout ?? options.ShutdownTimeout;
Expand Down Expand Up @@ -108,24 +108,11 @@ public void ApplyTo(SentryOptions options)
options.EnableSpotlight = EnableSpotlight ?? options.EnableSpotlight;
options.SpotlightUrl = SpotlightUrl ?? options.SpotlightUrl;

if (Experimental is { } experimental)
{
options.Experimental.EnableMetrics = experimental.EnableMetrics ?? options.Experimental.EnableMetrics;
}

#if ANDROID
Android.ApplyTo(options.Android);
Native.ApplyTo(options.Native);
#elif __IOS__
Native.ApplyTo(options.Native);
#endif
}

/// <summary>
/// Bindable Options for <see cref="SentryOptions.ExperimentalSentryOptions"/>.
/// </summary>
internal class ExperimentalSentryOptions
{
public bool? EnableMetrics { get; set; }
}
}
1 change: 0 additions & 1 deletion src/Sentry/Extensibility/DisabledHub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,5 @@ public void Dispose()
/// <summary>
/// Disabled Metrics.
/// </summary>
[Experimental("SENTRYTRACECONNECTEDMETRICS", UrlFormat = "https://github.com/getsentry/sentry-dotnet/discussions/4838")]
public SentryMetricEmitter Metrics => DisabledSentryMetricEmitter.Instance;
}
3 changes: 1 addition & 2 deletions src/Sentry/Extensibility/HubAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ private HubAdapter() { }
/// <summary>
/// Forwards the call to <see cref="SentrySdk"/>.
/// </summary>
[Experimental("SENTRYTRACECONNECTEDMETRICS", UrlFormat = "https://github.com/getsentry/sentry-dotnet/discussions/4838")]
public SentryMetricEmitter Metrics { [DebuggerStepThrough] get => SentrySdk.Experimental.Metrics; }
public SentryMetricEmitter Metrics { [DebuggerStepThrough] get => SentrySdk.Metrics; }

/// <summary>
/// Forwards the call to <see cref="SentrySdk"/>.
Expand Down
5 changes: 2 additions & 3 deletions src/Sentry/IHub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,10 @@ public interface IHub : ISentryClient, ISentryScopeManager
/// <remarks>
/// Available options:
/// <list type="bullet">
/// <item><see cref="Sentry.SentryOptions.ExperimentalSentryOptions.EnableMetrics"/></item>
/// <item><see cref="Sentry.SentryOptions.ExperimentalSentryOptions.SetBeforeSendMetric(System.Func{SentryMetric, SentryMetric})"/></item>
/// <item><see cref="Sentry.SentryOptions.EnableMetrics"/></item>
/// <item><see cref="Sentry.SentryOptions.SetBeforeSendMetric(System.Func{SentryMetric, SentryMetric})"/></item>
/// </list>
/// </remarks>
[Experimental("SENTRYTRACECONNECTEDMETRICS", UrlFormat = "https://github.com/getsentry/sentry-dotnet/discussions/4838")]
public SentryMetricEmitter Metrics { get; }

/// <summary>
Expand Down
4 changes: 2 additions & 2 deletions src/Sentry/Internal/DefaultSentryMetricEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ internal sealed class DefaultSentryMetricEmitter : SentryMetricEmitter, IDisposa
internal DefaultSentryMetricEmitter(IHub hub, SentryOptions options, ISystemClock clock, int batchCount, TimeSpan batchInterval)
{
Debug.Assert(hub.IsEnabled);
Debug.Assert(options.Experimental is { EnableMetrics: true });
Debug.Assert(options is { EnableMetrics: true });

_hub = hub;
_options = options;
Expand Down Expand Up @@ -69,7 +69,7 @@ private protected override void CaptureMetric<T>(SentryMetric<T> metric) where T

SentryMetric? configuredMetric = metric;

if (_options.Experimental.BeforeSendMetricInternal is { } beforeSendMetric)
if (_options.BeforeSendMetricInternal is { } beforeSendMetric)
{
try
{
Expand Down
2 changes: 1 addition & 1 deletion src/Sentry/SentryMetricEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ internal static SentryMetricEmitter Create(IHub hub, SentryOptions options, ISys

internal static SentryMetricEmitter Create(IHub hub, SentryOptions options, ISystemClock clock, int batchCount, TimeSpan batchInterval)
{
return options.Experimental.EnableMetrics
return options.EnableMetrics
? new DefaultSentryMetricEmitter(hub, options, clock, batchCount, batchInterval)
: DisabledSentryMetricEmitter.Instance;
}
Expand Down
73 changes: 26 additions & 47 deletions src/Sentry/SentryOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,32 @@ public void SetBeforeSendLog(Func<SentryLog, SentryLog?> beforeSendLog)
_beforeSendLog = beforeSendLog;
}

/// <summary>
/// When set to <see langword="false"/>, the SDK does not generate and send metrics to Sentry via <see cref="SentrySdk.Metrics"/>.
/// Defaults to <see langword="true"/>.
/// </summary>
/// <seealso href="https://develop.sentry.dev/sdk/telemetry/metrics/"/>
public bool EnableMetrics { get; set; } = true;

private Func<SentryMetric, SentryMetric?>? _beforeSendMetric;

internal Func<SentryMetric, SentryMetric?>? BeforeSendMetricInternal => _beforeSendMetric;

/// <summary>
/// Sets a callback function to be invoked before sending the metric to Sentry.
/// When the delegate throws an <see cref="Exception"/> during invocation, the metric will not be captured.
/// </summary>
/// <remarks>
/// It can be used to modify the metric object before being sent to Sentry.
/// To prevent the metric from being sent to Sentry, return <see langword="null"/>.
/// Supported numeric value types are <see langword="byte"/>, <see langword="short"/>, <see langword="int"/>, <see langword="long"/>, <see langword="float"/>, and <see langword="double"/>.
/// </remarks>
/// <seealso href="https://develop.sentry.dev/sdk/telemetry/metrics/"/>
public void SetBeforeSendMetric(Func<SentryMetric, SentryMetric?> beforeSendMetric)
{
_beforeSendMetric = beforeSendMetric;
}

private int _maxQueueItems = 30;

/// <summary>
Expand Down Expand Up @@ -1907,51 +1933,4 @@ internal static List<StringOrRegex> GetDefaultInAppExclude() =>
InAppExcludeRegexes.LibMonoSgen,
InAppExcludeRegexes.LibXamarin
];

/// <summary>
/// Sentry features that are currently in an experimental state.
/// </summary>
/// <remarks>
/// Experimental features are subject to binary, source and behavioral breaking changes in future updates.
/// </remarks>
public ExperimentalSentryOptions Experimental { get; } = new ExperimentalSentryOptions();

/// <summary>
/// Sentry features that are currently in an experimental state.
/// </summary>
/// <remarks>
/// Experimental features are subject to binary, source and behavioral breaking changes in future updates.
/// </remarks>
public class ExperimentalSentryOptions
{
private Func<SentryMetric, SentryMetric?>? _beforeSendMetric;

internal ExperimentalSentryOptions()
{
}

internal Func<SentryMetric, SentryMetric?>? BeforeSendMetricInternal => _beforeSendMetric;

/// <summary>
/// When set to <see langword="false"/>, the SDK does not generate and send metrics to Sentry via <see cref="SentrySdk"/>.
/// Defaults to <see langword="true"/>.
/// </summary>
/// <seealso href="https://develop.sentry.dev/sdk/telemetry/metrics/"/>
public bool EnableMetrics { get; set; } = true;

/// <summary>
/// Sets a callback function to be invoked before sending the metric to Sentry.
/// When the delegate throws an <see cref="Exception"/> during invocation, the metric will not be captured.
/// </summary>
/// <remarks>
/// It can be used to modify the metric object before being sent to Sentry.
/// To prevent the metric from being sent to Sentry, return <see langword="null"/>.
/// Supported numeric value types are <see langword="byte"/>, <see langword="short"/>, <see langword="int"/>, <see langword="long"/>, <see langword="float"/>, and <see langword="double"/>.
/// </remarks>
/// <seealso href="https://develop.sentry.dev/sdk/telemetry/metrics/"/>
public void SetBeforeSendMetric(Func<SentryMetric, SentryMetric?> beforeSendMetric)
{
_beforeSendMetric = beforeSendMetric;
}
}
}
29 changes: 3 additions & 26 deletions src/Sentry/SentrySdk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,9 @@ public void Dispose()
/// <inheritdoc cref="IHub.Logger" />
public static SentryStructuredLogger Logger { [DebuggerStepThrough] get => CurrentHub.Logger; }

/// <inheritdoc cref="IHub.Metrics" />
public static SentryMetricEmitter Metrics { [DebuggerStepThrough] get => CurrentHub.Metrics; }

/// <summary>
/// Creates a new scope that will terminate when disposed.
/// </summary>
Expand Down Expand Up @@ -857,30 +860,4 @@ public static void CauseCrash(CrashType crashType)
[DllImport("libc", EntryPoint = "strlen")]
private static extern IntPtr NativeStrlenLibC(IntPtr strt);
#endif

/// <summary>
/// Sentry features that are currently in an experimental state.
/// </summary>
/// <remarks>
/// Experimental features are subject to binary, source and behavioral breaking changes in future updates.
/// </remarks>
public static ExperimentalSentrySdk Experimental { get; } = new();

/// <summary>
/// Sentry features that are currently in an experimental state.
/// </summary>
/// <remarks>
/// Experimental features are subject to binary, source and behavioral breaking changes in future updates.
/// </remarks>
public sealed class ExperimentalSentrySdk
{
internal ExperimentalSentrySdk()
{
}

#pragma warning disable SENTRYTRACECONNECTEDMETRICS
/// <inheritdoc cref="IHub.Metrics" />
public SentryMetricEmitter Metrics { [DebuggerStepThrough] get => CurrentHub.Metrics; }
#pragma warning restore SENTRYTRACECONNECTEDMETRICS
}
}
1 change: 0 additions & 1 deletion test/Sentry.Testing/BindableTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ private static IEnumerable<PropertyInfo> GetBindableProperties(IEnumerable<strin
!p.PropertyType.IsSubclassOf(typeof(Delegate)) // Exclude delegate properties
&& !p.PropertyType.IsInterface // Exclude interface properties
&& !skipProperties.Contains(p.Name) // Exclude any properties explicitly excluded by derived classes
&& p.PropertyType != typeof(SentryOptions.ExperimentalSentryOptions) // Exclude the Experimental sub-properties

// Exclude the Mobile sub-properties
#if ANDROID
Expand Down
17 changes: 3 additions & 14 deletions test/Sentry.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,6 @@ namespace Sentry
bool IsSessionActive { get; }
Sentry.SentryId LastEventId { get; }
Sentry.SentryStructuredLogger Logger { get; }
[System.Diagnostics.CodeAnalysis.Experimental("SENTRYTRACECONNECTEDMETRICS", UrlFormat="https://github.com/getsentry/sentry-dotnet/discussions/4838")]
Sentry.SentryMetricEmitter Metrics { get; }
void BindException(System.Exception exception, Sentry.ISpan span);
Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, System.Action<Sentry.Scope> configureScope);
Expand Down Expand Up @@ -806,10 +805,10 @@ namespace Sentry
public string? Dsn { get; set; }
public bool EnableBackpressureHandling { get; set; }
public bool EnableLogs { get; set; }
public bool EnableMetrics { get; set; }
public bool EnableScopeSync { get; set; }
public bool EnableSpotlight { get; set; }
public string? Environment { get; set; }
public Sentry.SentryOptions.ExperimentalSentryOptions Experimental { get; }
public System.Collections.Generic.IList<Sentry.HttpStatusCodeRange> FailedRequestStatusCodes { get; set; }
public System.Collections.Generic.IList<Sentry.StringOrRegex> FailedRequestTargets { get; set; }
public System.TimeSpan FlushTimeout { get; set; }
Expand Down Expand Up @@ -894,14 +893,10 @@ namespace Sentry
public void SetBeforeSend(System.Func<Sentry.SentryEvent, Sentry.SentryEvent?> beforeSend) { }
public void SetBeforeSend(System.Func<Sentry.SentryEvent, Sentry.SentryHint, Sentry.SentryEvent?> beforeSend) { }
public void SetBeforeSendLog(System.Func<Sentry.SentryLog, Sentry.SentryLog?> beforeSendLog) { }
public void SetBeforeSendMetric(System.Func<Sentry.SentryMetric, Sentry.SentryMetric?> beforeSendMetric) { }
public void SetBeforeSendTransaction(System.Func<Sentry.SentryTransaction, Sentry.SentryTransaction?> beforeSendTransaction) { }
public void SetBeforeSendTransaction(System.Func<Sentry.SentryTransaction, Sentry.SentryHint, Sentry.SentryTransaction?> beforeSendTransaction) { }
public Sentry.SentryOptions UseStackTraceFactory(Sentry.Extensibility.ISentryStackTraceFactory sentryStackTraceFactory) { }
public class ExperimentalSentryOptions
{
public bool EnableMetrics { get; set; }
public void SetBeforeSendMetric(System.Func<Sentry.SentryMetric, Sentry.SentryMetric?> beforeSendMetric) { }
}
}
public sealed class SentryPackage : Sentry.ISentryJsonSerializable
{
Expand Down Expand Up @@ -931,11 +926,11 @@ namespace Sentry
}
public static class SentrySdk
{
public static Sentry.SentrySdk.ExperimentalSentrySdk Experimental { get; }
public static bool IsEnabled { get; }
public static bool IsSessionActive { get; }
public static Sentry.SentryId LastEventId { get; }
public static Sentry.SentryStructuredLogger Logger { get; }
public static Sentry.SentryMetricEmitter Metrics { get; }
public static void AddBreadcrumb(Sentry.Breadcrumb breadcrumb, Sentry.SentryHint? hint = null) { }
public static void AddBreadcrumb(string message, string? category = null, string? type = null, System.Collections.Generic.IDictionary<string, string>? data = null, Sentry.BreadcrumbLevel level = 0) { }
public static void AddBreadcrumb(Sentry.Infrastructure.ISystemClock? clock, string message, string? category = null, string? type = null, System.Collections.Generic.IDictionary<string, string>? data = null, Sentry.BreadcrumbLevel level = 0) { }
Expand Down Expand Up @@ -995,10 +990,6 @@ namespace Sentry
public static Sentry.ITransactionTracer StartTransaction(string name, string operation, Sentry.SentryTraceHeader traceHeader) { }
public static Sentry.ITransactionTracer StartTransaction(string name, string operation, string? description) { }
public static void UnsetTag(string key) { }
public sealed class ExperimentalSentrySdk
{
public Sentry.SentryMetricEmitter Metrics { get; }
}
}
public class SentrySession : Sentry.ISentrySession
{
Expand Down Expand Up @@ -1490,7 +1481,6 @@ namespace Sentry.Extensibility
public bool IsSessionActive { get; }
public Sentry.SentryId LastEventId { get; }
public Sentry.SentryStructuredLogger Logger { get; }
[System.Diagnostics.CodeAnalysis.Experimental("SENTRYTRACECONNECTEDMETRICS", UrlFormat="https://github.com/getsentry/sentry-dotnet/discussions/4838")]
public Sentry.SentryMetricEmitter Metrics { get; }
public void BindClient(Sentry.ISentryClient client) { }
public void BindException(System.Exception exception, Sentry.ISpan span) { }
Expand Down Expand Up @@ -1539,7 +1529,6 @@ namespace Sentry.Extensibility
public bool IsSessionActive { get; }
public Sentry.SentryId LastEventId { get; }
public Sentry.SentryStructuredLogger Logger { get; }
[System.Diagnostics.CodeAnalysis.Experimental("SENTRYTRACECONNECTEDMETRICS", UrlFormat="https://github.com/getsentry/sentry-dotnet/discussions/4838")]
public Sentry.SentryMetricEmitter Metrics { get; }
public void AddBreadcrumb(string message, string? category = null, string? type = null, System.Collections.Generic.IDictionary<string, string>? data = null, Sentry.BreadcrumbLevel level = 0) { }
public void AddBreadcrumb(Sentry.Infrastructure.ISystemClock clock, string message, string? category = null, string? type = null, System.Collections.Generic.IDictionary<string, string>? data = null, Sentry.BreadcrumbLevel level = 0) { }
Expand Down
Loading
Loading