Skip to content

fix: include Data set via ITransactionTracer in SentryTransaction#4148

Merged
jamescrosswell merged 12 commits intomainfrom
fix/transaction/tracer-setdata-not-sent
Mar 19, 2026
Merged

fix: include Data set via ITransactionTracer in SentryTransaction#4148
jamescrosswell merged 12 commits intomainfrom
fix/transaction/tracer-setdata-not-sent

Conversation

@Flash0ver
Copy link
Copy Markdown
Member

@Flash0ver Flash0ver commented Apr 28, 2025

fixes #4140

relates to #3936

Changes

  • remove backing store of SentryTransaction.Data
  • reuse Data of SentryContexts.Trace instead

Added links to discussions from the original PR (if I understood all the context correctly).
Added questions where I am uncertain whether it's the correct way of fixing the issue.

@Flash0ver Flash0ver self-assigned this Apr 28, 2025
@Flash0ver Flash0ver requested a review from Copilot April 28, 2025 09:51
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.


/// <inheritdoc />
public void SetData(string key, object? value) => _data[key] = value;
public void SetData(string key, object? value) => _contexts.Trace.SetData(key, value);
Copy link
Copy Markdown
Member Author

@Flash0ver Flash0ver Apr 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: concurrency

The now used

private Dictionary<string, object?> _data = new();

currently is a regular Dictionary`2.
Should this now become a ConcurrentDictionary`2?
Because it's also the private readonly ConcurrentDictionary<string, object?> _data = new(); that this PR removes from this type?

Or is that an indicator that this fix is technically not quite right?

Relates to #3936 (comment) and #3936 (comment)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SentryTransaction shouldn't be accessed concurrently since it represents "a point in time" instance that gets serialized to Sentry.

The TransactionTracer is potentially accessed concurrently (we set it onto the Scope which has concurrent access in both global mode (every ConfigureScope call access the same scope instance) or non global mode (since even though there's a single Scope instance per thread, we do access/read things in order to make clones for new threads).

Throwing Concurrent around is not always the solution. In this case for sure not since we want SentryTrasaction to be a snapshot, so we need a deep clone here. We don't want just a clone of the collection if the items in the collection are mutable. I wrote a note above about this.

If things on the context are immutable, things are easier though we could have data loss if we have concurrent updates without synchronization.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm... I see what you're saying. In the original code the TrancactionTracer stored additional data in private readonly ConcurrentDictionary<string, object?> _data = new();

In the new code that data instead gets stored in _contexts.Trace._data which is private Dictionary<string, object?> _data = new();.

So yes, I think we should probably make the this a concurrent dictionary:

private Dictionary<string, object?> _data = new();

/// <inheritdoc />
public IReadOnlyDictionary<string, object?> Data => _data;

public IReadOnlyDictionary<string, object?> Data => _contexts.Trace.Data;
Copy link
Copy Markdown
Member Author

@Flash0ver Flash0ver Apr 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: reference Contexts in SentryTransaction vs copy Contexts to SentryTransaction

When creating a SentryTransaction from ITransactionTracer, we reference the SentryContexts:

Contexts = tracer.Contexts;

Should we instead copy the Contexts (via e.g. SentryContexts.Clone)?

Or is that an indicator that this fix here is not quite right, technically?
Should we maybe, rather than have SetData writing into SentryContexts.Trace.Data directly, instead when creating the SentryTransaction from the ITransactionTracer copy the ITransactionTracer.Data (backed by it's own Dictionary`2) over to the Context of the new SentryTransaction.
E.g. something like

class SentryTransaction
{
  public SentryTransaction(ITransactionTracer tracer) : this(tracer.Name, tracer.NameSource)
  {
    Contexts = tracer.Contexts;
    foreach (KeyValuePair<string, object?> data in tracer.Data)
    {
      Contexts.Trace.SetData(data.Key, data.Value);
    }
  }
}

or similar.
But that would have a side-effect on the Contexts of TransactionTracer, which I don't think is expected when creating a new SentryTransaction from TransactionTracer.
Should we perhaps indeed make a copy of the Trace and/or SentryContext?

Relates to #3936 (comment)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think at this point the tracer is immutable - we're capturing the transaction trace so the trace should be finished and won't change.

Comment on lines +26 to +29
Data: {
http.request.method: GET,
http.response.status_code: 200
}
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: from

return o;
});

Assert.Contains($$"""
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: I kept this test similar to

public async Task SerializeObject_AllPropertiesSetToNonDefault_SerializesValidObject()

which also does a serialize/deserialize-roundtrip test
plus an additional "Contains-JSON" check on the serialized string

/// <inheritdoc />
public IReadOnlyDictionary<string, object?> Data => _data;

public IReadOnlyDictionary<string, object?> Data => _contexts.Trace.Data;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that if you're copying all objects from the collection while they are mutable and still on the scope, mutations done on the scope will be reflected on the transaction object resulting in possible inaccurate data being sent to Sentry, or potentially crashes when we read the data for serialization while the data is being mutated


/// <inheritdoc />
public void SetData(string key, object? value) => _data[key] = value;
public void SetData(string key, object? value) => _contexts.Trace.SetData(key, value);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SentryTransaction shouldn't be accessed concurrently since it represents "a point in time" instance that gets serialized to Sentry.

The TransactionTracer is potentially accessed concurrently (we set it onto the Scope which has concurrent access in both global mode (every ConfigureScope call access the same scope instance) or non global mode (since even though there's a single Scope instance per thread, we do access/read things in order to make clones for new threads).

Throwing Concurrent around is not always the solution. In this case for sure not since we want SentryTrasaction to be a snapshot, so we need a deep clone here. We don't want just a clone of the collection if the items in the collection are mutable. I wrote a note above about this.

If things on the context are immutable, things are easier though we could have data loss if we have concurrent updates without synchronization.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 18, 2026

Semver Impact of This PR

None (no version bump detected)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


Breaking Changes 🛠

  • The _Metrics_ APIs are now stable: removed Experimental from SentrySdk, SentryOptions and IHub by Flash0ver in #5023

Features ✨

  • Report a new _Diagnostic_ (SENTRY1001) when a Metrics-API is invoked with an unsupported numeric type by Flash0ver in #4840

Fixes 🐛

  • fix: include Data set via ITransactionTracer in SentryTransaction by Flash0ver in #4148
  • fix: CaptureFeedback now applies event processors by jamescrosswell in #4942

Dependencies ⬆️

Deps

  • chore(deps): update Cocoa SDK to v9.7.0 by github-actions in #5015
  • chore(deps): update Java SDK to v8.35.0 by github-actions in #5017
  • chore(deps): replaced the heavy protobuf-javalite 3.25.8 dependency with a light-weight epitaph 0.1.0 alternative on Android (getsentry/sentry-java#5157) by github-actions in #5017
  • chore(deps): update CLI to v3.3.3 by github-actions in #5002
  • chore(deps): update Cocoa SDK to v9.6.0 by github-actions in #4958

Other

  • ref: Use .NET 6.0 ArgumentNullException throw helpers by copilot-swe-agent in #4985

🤖 This preview updates automatically when you update the PR.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 18, 2026

Codecov Report

❌ Patch coverage is 85.71429% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.00%. Comparing base (a4a8ded) to head (454ceaf).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/Sentry/Internal/Extensions/JsonExtensions.cs 66.66% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4148      +/-   ##
==========================================
- Coverage   74.03%   74.00%   -0.03%     
==========================================
  Files         499      499              
  Lines       18044    18049       +5     
  Branches     3510     3512       +2     
==========================================
- Hits        13358    13357       -1     
- Misses       3830     3838       +8     
+ Partials      856      854       -2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

Copy link
Copy Markdown
Collaborator

@jamescrosswell jamescrosswell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome - thanks @Flash0ver !

@jamescrosswell jamescrosswell merged commit 58c1a81 into main Mar 19, 2026
45 checks passed
@jamescrosswell jamescrosswell deleted the fix/transaction/tracer-setdata-not-sent branch March 19, 2026 03:18
evgenygunko pushed a commit to evgenygunko/CopyWordsDA that referenced this pull request Mar 31, 2026
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [Sentry.Maui](https://sentry.io/) ([source](https://github.com/getsentry/sentry-dotnet)) | nuget | minor | `6.2.0` -> `6.3.0` |

---

### Release Notes

<details>
<summary>getsentry/sentry-dotnet (Sentry.Maui)</summary>

### [`v6.3.0`](https://github.com/getsentry/sentry-dotnet/blob/HEAD/CHANGELOG.md#630)

[Compare Source](getsentry/sentry-dotnet@6.2.0...6.3.0)

##### Features

-   The *Metrics* APIs are now stable: removed `Experimental` from `SentrySdk`, `SentryOptions` and `IHub` ([#&#8203;5023](getsentry/sentry-dotnet#5023))
-   Report a new *Diagnostic* (`SENTRY1001`) when a Metrics-API is invoked with an unsupported numeric type ([#&#8203;4840](getsentry/sentry-dotnet#4840))

##### Fixes

-   Common tags such as `Environment` and `Release` and custom event processors are all now correctly applied to CaptureFeedback events ([#&#8203;4942](getsentry/sentry-dotnet#4942))
-   Include `Data` set via `ITransactionTracer` in `SentryTransaction` ([#&#8203;4148](getsentry/sentry-dotnet#4148))

##### Dependencies

-   Bump Cocoa SDK from v9.5.0 to v9.7.0 ([#&#8203;4958](getsentry/sentry-dotnet#4958), [#&#8203;5015](getsentry/sentry-dotnet#5015))
-   Bump CLI from v3.3.0 to v3.3.3 ([#&#8203;5002](getsentry/sentry-dotnet#5002))
-   Bump Java SDK from v8.34.1 to v8.35.0 ([#&#8203;5017](getsentry/sentry-dotnet#5017))
-   Bump Native SDK from v0.13.2 to v0.13.3 ([#&#8203;5045](getsentry/sentry-dotnet#5045))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or PR is renamed to start with "rebase!".

👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://github.com/renovatebot/renovate/discussions) if that's undesired.

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
github-merge-queue bot pushed a commit to DFE-Digital/teaching-record-system that referenced this pull request Apr 1, 2026
…3244)

Pinned [Sentry.AspNetCore](https://github.com/getsentry/sentry-dotnet)
at 6.3.0.

<details>
<summary>Release notes</summary>

_Sourced from [Sentry.AspNetCore's
releases](https://github.com/getsentry/sentry-dotnet/releases)._

## 6.3.0

### Features

- The _Metrics_ APIs are now stable: removed `Experimental` from
`SentrySdk`, `SentryOptions` and `IHub`
([#​5023](getsentry/sentry-dotnet#5023))
- Report a new _Diagnostic_ (`SENTRY1001`) when a Metrics-API is invoked
with an unsupported numeric type
([#​4840](getsentry/sentry-dotnet#4840))

### Fixes

- Common tags such as `Environment` and `Release` and custom event
processors are all now correctly applied to CaptureFeedback events
([#​4942](getsentry/sentry-dotnet#4942))
- Include `Data` set via `ITransactionTracer` in `SentryTransaction`
([#​4148](getsentry/sentry-dotnet#4148))

### Dependencies

- Bump Cocoa SDK from v9.5.0 to v9.7.0
([#​4958](getsentry/sentry-dotnet#4958),
[#​5015](getsentry/sentry-dotnet#5015))
- Bump CLI from v3.3.0 to v3.3.3
([#​5002](getsentry/sentry-dotnet#5002))
- Bump Java SDK from v8.34.1 to v8.35.0
([#​5017](getsentry/sentry-dotnet#5017))
- Bump Native SDK from v0.13.2 to v0.13.3
([#​5045](getsentry/sentry-dotnet#5045))

Commits viewable in [compare
view](getsentry/sentry-dotnet@6.2.0...6.3.0).
</details>

Updated
[Sentry.Extensions.Logging](https://github.com/getsentry/sentry-dotnet)
from 6.2.0 to 6.3.0.

<details>
<summary>Release notes</summary>

_Sourced from [Sentry.Extensions.Logging's
releases](https://github.com/getsentry/sentry-dotnet/releases)._

## 6.3.0

### Features

- The _Metrics_ APIs are now stable: removed `Experimental` from
`SentrySdk`, `SentryOptions` and `IHub`
([#​5023](getsentry/sentry-dotnet#5023))
- Report a new _Diagnostic_ (`SENTRY1001`) when a Metrics-API is invoked
with an unsupported numeric type
([#​4840](getsentry/sentry-dotnet#4840))

### Fixes

- Common tags such as `Environment` and `Release` and custom event
processors are all now correctly applied to CaptureFeedback events
([#​4942](getsentry/sentry-dotnet#4942))
- Include `Data` set via `ITransactionTracer` in `SentryTransaction`
([#​4148](getsentry/sentry-dotnet#4148))

### Dependencies

- Bump Cocoa SDK from v9.5.0 to v9.7.0
([#​4958](getsentry/sentry-dotnet#4958),
[#​5015](getsentry/sentry-dotnet#5015))
- Bump CLI from v3.3.0 to v3.3.3
([#​5002](getsentry/sentry-dotnet#5002))
- Bump Java SDK from v8.34.1 to v8.35.0
([#​5017](getsentry/sentry-dotnet#5017))
- Bump Native SDK from v0.13.2 to v0.13.3
([#​5045](getsentry/sentry-dotnet#5045))

Commits viewable in [compare
view](getsentry/sentry-dotnet@6.2.0...6.3.0).
</details>

Pinned [Sentry.Serilog](https://github.com/getsentry/sentry-dotnet) at
6.3.0.

<details>
<summary>Release notes</summary>

_Sourced from [Sentry.Serilog's
releases](https://github.com/getsentry/sentry-dotnet/releases)._

## 6.3.0

### Features

- The _Metrics_ APIs are now stable: removed `Experimental` from
`SentrySdk`, `SentryOptions` and `IHub`
([#​5023](getsentry/sentry-dotnet#5023))
- Report a new _Diagnostic_ (`SENTRY1001`) when a Metrics-API is invoked
with an unsupported numeric type
([#​4840](getsentry/sentry-dotnet#4840))

### Fixes

- Common tags such as `Environment` and `Release` and custom event
processors are all now correctly applied to CaptureFeedback events
([#​4942](getsentry/sentry-dotnet#4942))
- Include `Data` set via `ITransactionTracer` in `SentryTransaction`
([#​4148](getsentry/sentry-dotnet#4148))

### Dependencies

- Bump Cocoa SDK from v9.5.0 to v9.7.0
([#​4958](getsentry/sentry-dotnet#4958),
[#​5015](getsentry/sentry-dotnet#5015))
- Bump CLI from v3.3.0 to v3.3.3
([#​5002](getsentry/sentry-dotnet#5002))
- Bump Java SDK from v8.34.1 to v8.35.0
([#​5017](getsentry/sentry-dotnet#5017))
- Bump Native SDK from v0.13.2 to v0.13.3
([#​5045](getsentry/sentry-dotnet#5045))

Commits viewable in [compare
view](getsentry/sentry-dotnet@6.2.0...6.3.0).
</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TransactionTracer.SetData is not equivalent to TransactionTracer.Contexts.Trace.SetData

4 participants