Skip to content
Draft
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
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,28 @@

## Unreleased

### BREAKING CHANGES

- Rename [Trace-connected Metrics](https://docs.sentry.io/product/explore/metrics/) APIs to avoid implying aggregation ([#4834](https://github.com/getsentry/sentry-dotnet/pull/4834))
- from `AddCounter` to `EmitCounter`
- from `RecordDistribution` to `EmitDistribution`
- from `RecordGauge` to `EmitGauge`

### Features

- Validate [Trace-connected Metrics](https://docs.sentry.io/product/explore/metrics/) ([#4834](https://github.com/getsentry/sentry-dotnet/pull/4834))

### Fixes

- Attributes for [Trace-connected Metrics](https://docs.sentry.io/product/explore/metrics/) set via `SetBeforeSendLog` callback ([#4834](https://github.com/getsentry/sentry-dotnet/pull/4834))
- Disallow unsupported 128-bit floating point numbers (i.e. `decimal`) for [Trace-connected Metrics](https://docs.sentry.io/product/explore/metrics/) ([#4834](https://github.com/getsentry/sentry-dotnet/pull/4834))

## 6.1.0-alpha.1

### Features

- Extended `SentryThread` by `Main` to allow indication whether the thread is considered the current main thread ([#4807](https://github.com/getsentry/sentry-dotnet/pull/4807))
- Add _experimental_ support for [Sentry trace-connected Metrics](https://docs.sentry.io/product/explore/metrics/) ([#4834](https://github.com/getsentry/sentry-dotnet/pull/4834))

### Dependencies

Expand Down
3 changes: 2 additions & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project>

<PropertyGroup>
<VersionPrefix>6.0.0</VersionPrefix>
<VersionPrefix>6.1.0-alpha.1</VersionPrefix>
<LangVersion>13</LangVersion>
<AccelerateBuildsInVisualStudio>true</AccelerateBuildsInVisualStudio>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
Expand All @@ -13,6 +13,7 @@

<!-- 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
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
using BenchmarkDotNet.Attributes;
using Sentry.Extensibility;
using Sentry.Internal;
using Sentry.Protocol;

namespace Sentry.Benchmarks;

public class StructuredLogBatchProcessorBenchmarks
/// <summary>
/// <see cref="BatchProcessor{TItem}"/> (formerly "Sentry.Internal.StructuredLogBatchProcessor") was originally developed as Batch Processor for Logs only.
/// When adding support for Trace-connected Metrics, which are quite similar to Logs, it has been made generic to support both.
/// For comparability of results, we still benchmark with <see cref="SentryLog"/>, rather than <see cref="SentryMetric"/>.
/// </summary>
public class BatchProcessorBenchmarks
{
private Hub _hub;
private StructuredLogBatchProcessor _batchProcessor;
private BatchProcessor<SentryLog> _batchProcessor;
private SentryLog _log;

[Params(10, 100)]
Expand All @@ -29,7 +35,7 @@ public void Setup()
var clientReportRecorder = new NullClientReportRecorder();

_hub = new Hub(options, DisabledHub.Instance);
_batchProcessor = new StructuredLogBatchProcessor(_hub, BatchCount, batchInterval, clientReportRecorder, null);
_batchProcessor = new BatchProcessor<SentryLog>(_hub, BatchCount, batchInterval, StructuredLog.Capture, clientReportRecorder, null);
_log = new SentryLog(DateTimeOffset.Now, SentryId.Empty, SentryLogLevel.Trace, "message");
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
```

BenchmarkDotNet v0.13.12, macOS 26.1 (25B78) [Darwin 25.1.0]
Apple M3 Pro, 1 CPU, 12 logical and 12 physical cores
.NET SDK 10.0.100
[Host] : .NET 8.0.14 (8.0.1425.11118), Arm64 RyuJIT AdvSIMD
DefaultJob : .NET 8.0.14 (8.0.1425.11118), Arm64 RyuJIT AdvSIMD


```
| Method | BatchCount | OperationsPerInvoke | Mean | Error | StdDev | Median | Gen0 | Allocated |
|------------------------- |----------- |-------------------- |-------------:|------------:|-------------:|-------------:|-------:|----------:|
| **EnqueueAndFlush** | **10** | **100** | **1,896.9 ns** | **9.94 ns** | **8.81 ns** | **1,894.2 ns** | **0.6104** | **5 KB** |
| EnqueueAndFlush_Parallel | 10 | 100 | 16,520.9 ns | 327.78 ns | 746.51 ns | 16,350.4 ns | 1.1292 | 9.29 KB |
| **EnqueueAndFlush** | **10** | **200** | **4,085.5 ns** | **80.03 ns** | **74.86 ns** | **4,087.1 ns** | **1.2207** | **10 KB** |
| EnqueueAndFlush_Parallel | 10 | 200 | 39,371.8 ns | 776.85 ns | 1,360.59 ns | 38,725.0 ns | 1.6479 | 13.6 KB |
| **EnqueueAndFlush** | **10** | **1000** | **18,829.3 ns** | **182.18 ns** | **142.24 ns** | **18,836.4 ns** | **6.1035** | **50 KB** |
| EnqueueAndFlush_Parallel | 10 | 1000 | 151,934.1 ns | 2,631.83 ns | 3,232.12 ns | 151,495.9 ns | 3.6621 | 31.31 KB |
| **EnqueueAndFlush** | **100** | **100** | **864.9 ns** | **2.16 ns** | **1.68 ns** | **865.0 ns** | **0.1469** | **1.2 KB** |
| EnqueueAndFlush_Parallel | 100 | 100 | 7,414.9 ns | 74.86 ns | 70.02 ns | 7,405.9 ns | 0.5722 | 4.61 KB |
| **EnqueueAndFlush** | **100** | **200** | **1,836.9 ns** | **15.28 ns** | **12.76 ns** | **1,834.9 ns** | **0.2937** | **2.41 KB** |
| EnqueueAndFlush_Parallel | 100 | 200 | 37,119.5 ns | 726.04 ns | 1,252.39 ns | 36,968.9 ns | 0.8545 | 7.27 KB |
| **EnqueueAndFlush** | **100** | **1000** | **8,567.2 ns** | **84.25 ns** | **74.68 ns** | **8,547.4 ns** | **1.4648** | **12.03 KB** |
| EnqueueAndFlush_Parallel | 100 | 1000 | 255,284.5 ns | 5,095.08 ns | 12,593.77 ns | 258,313.9 ns | 1.9531 | 19.02 KB |

This file was deleted.

3 changes: 3 additions & 0 deletions src/Sentry.Compiler.Extensions/AnalyzerReleases.Shipped.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
; Shipped analyzer releases
; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
; Unshipped analyzer release
; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md

### New Rules

Rule ID | Category | Severity | Notes
--------|----------|----------|-------
SENTRY1001 | Support | Warning | TraceConnectedMetricsAnalyzer
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using System;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;

namespace Sentry.Compiler.Extensions.Analyzers;

/// <summary>
/// Guide consumers to use the public API of <see href="https://develop.sentry.dev/sdk/telemetry/metrics/">Sentry Trace-connected Metrics</see> correctly.
/// </summary>
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class TraceConnectedMetricsAnalyzer : DiagnosticAnalyzer
{
private static readonly string Title = "Unsupported numeric type of Metric";
private static readonly string MessageFormat = "{0} is unsupported type for Sentry Metrics. The only supported types are byte, short, int, long, float, and double.";
private static readonly string Description = "Integers should be a 64-bit signed integer, while doubles should be a 64-bit floating point number.";

private static readonly DiagnosticDescriptor Rule = new(
id: DiagnosticIds.Sentry1001,
title: Title,
messageFormat: MessageFormat,
category: DiagnosticCategories.Support,
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true,
description: Description,
helpLinkUri: null
);

/// <inheritdoc />
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(Rule);

/// <inheritdoc />
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();

context.RegisterOperationAction(Execute, OperationKind.Invocation);
}

private static void Execute(OperationAnalysisContext context)
{
Debug.Assert(context.Operation.Language == LanguageNames.CSharp);
Debug.Assert(context.Operation.Kind is OperationKind.Invocation);

context.CancellationToken.ThrowIfCancellationRequested();

if (context.Operation is not IInvocationOperation invocation)
{
return;
}

var method = invocation.TargetMethod;
if (method.DeclaredAccessibility != Accessibility.Public || method.IsAbstract || method.IsVirtual || method.IsStatic || !method.ReturnsVoid || method.Parameters.Length == 0)
{
return;
}

if (!method.IsGenericMethod || method.Arity != 1 || method.TypeArguments.Length != 1)
{
return;
}

if (method.ContainingAssembly is null || method.ContainingAssembly.Name != "Sentry")
{
return;
}

if (method.ContainingNamespace is null || method.ContainingNamespace.Name != "Sentry")
{
return;
}

string fullyQualifiedMetadataName;
if (method.Name is "EmitCounter" or "EmitGauge" or "EmitDistribution")
{
fullyQualifiedMetadataName = "Sentry.SentryTraceMetrics";
}
else if (method.Name is "SetBeforeSendMetric")
{
fullyQualifiedMetadataName = "Sentry.SentryOptions+ExperimentalSentryOptions";
}
else
{
return;
}

var typeArgument = method.TypeArguments[0];
if (typeArgument.SpecialType is SpecialType.System_Byte or SpecialType.System_Int16 or SpecialType.System_Int32 or SpecialType.System_Int64 or SpecialType.System_Single or SpecialType.System_Double)
{
return;
}

if (typeArgument is ITypeParameterSymbol)
{
return;
}

var sentryType = context.Compilation.GetTypeByMetadataName(fullyQualifiedMetadataName);
if (sentryType is null)
{
return;
}

if (!SymbolEqualityComparer.Default.Equals(method.ContainingType, sentryType))
{
return;
}

var location = invocation.Syntax.GetLocation();
var diagnostic = Diagnostic.Create(Rule, location, typeArgument.ToDisplayString(SymbolDisplayFormats.FullNameFormat));
context.ReportDiagnostic(diagnostic);
}
}
6 changes: 6 additions & 0 deletions src/Sentry.Compiler.Extensions/DiagnosticCategories.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Sentry.Compiler.Extensions;

internal static class DiagnosticCategories
{
internal const string Support = nameof(Support);
}
6 changes: 6 additions & 0 deletions src/Sentry.Compiler.Extensions/DiagnosticIds.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Sentry.Compiler.Extensions;

internal static class DiagnosticIds
{
internal const string Sentry1001 = "SENTRY1001";
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,25 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.3.1" PrivateAssets="all"/>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.3.1" PrivateAssets="all" />
</ItemGroup>

<!--
We use Simon Cropp's Polyfill source-only package to access APIs in lower targets.
https://github.com/SimonCropp/Polyfill
-->
<ItemGroup>
<PackageReference Include="Polyfill" Version="1.32.0" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
<Using Remove="System.Text.Json" />
<Using Remove="System.Text.Json.Serialization" />
</ItemGroup>

<ItemGroup>
<AdditionalFiles Remove="AnalyzerReleases.Shipped.md" />
<AdditionalFiles Remove="AnalyzerReleases.Unshipped.md" />
</ItemGroup>

</Project>
12 changes: 12 additions & 0 deletions src/Sentry.Compiler.Extensions/SymbolDisplayFormats.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Microsoft.CodeAnalysis;

namespace Sentry.Compiler.Extensions;

internal static class SymbolDisplayFormats
{
internal static SymbolDisplayFormat FullNameFormat { get; } = new SymbolDisplayFormat(
globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Omitted,
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters
);
}
17 changes: 16 additions & 1 deletion src/Sentry/BindableSentryOptions.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace Sentry;

/// <summary>
/// Contains representations of the subset of properties in SentryOptions that can be set from ConfigurationBindings.
/// Contains representations of the subset of properties in <see cref="SentryOptions"/> that can be set from ConfigurationBindings.
/// Note that all of these properties are nullable, so that if they are not present in configuration, the values from
/// the type being bound to will be preserved.
/// </summary>
Expand Down Expand Up @@ -56,6 +56,8 @@ 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 Down Expand Up @@ -106,11 +108,24 @@ 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; }
}
}
7 changes: 6 additions & 1 deletion src/Sentry/Extensibility/DisabledHub.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using Sentry.Internal;
using Sentry.Protocol.Envelopes;
using Sentry.Protocol.Metrics;

namespace Sentry.Extensibility;

Expand Down Expand Up @@ -267,4 +266,10 @@ public void Dispose()
/// Disabled Logger.
/// </summary>
public SentryStructuredLogger Logger => DisabledSentryStructuredLogger.Instance;

/// <summary>
/// Disabled Metrics.
/// </summary>
[Experimental("SENTRYTRACECONNECTEDMETRICS", UrlFormat = "https://github.com/getsentry/sentry-dotnet/discussions/4838")]
public SentryTraceMetrics Metrics => DisabledSentryTraceMetrics.Instance;
}
7 changes: 6 additions & 1 deletion src/Sentry/Extensibility/HubAdapter.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using Sentry.Infrastructure;
using Sentry.Protocol.Envelopes;
using Sentry.Protocol.Metrics;

namespace Sentry.Extensibility;

Expand Down Expand Up @@ -37,6 +36,12 @@ private HubAdapter() { }
/// </summary>
public SentryStructuredLogger Logger { [DebuggerStepThrough] get => SentrySdk.Logger; }

/// <summary>
/// Forwards the call to <see cref="SentrySdk"/>.
/// </summary>
[Experimental("SENTRYTRACECONNECTEDMETRICS", UrlFormat = "https://github.com/getsentry/sentry-dotnet/discussions/4838")]
public SentryTraceMetrics Metrics { [DebuggerStepThrough] get => SentrySdk.Experimental.Metrics; }

/// <summary>
/// Forwards the call to <see cref="SentrySdk"/>.
/// </summary>
Expand Down
Loading
Loading