- 
          
- 
                Notifications
    You must be signed in to change notification settings 
- Fork 225
          fix: include Data set via ITransactionTracer in SentryTransaction
          #4148
        
          New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
e6e6c9b
              f57868e
              31e9125
              13c2a16
              cb9e0c3
              3db4876
              e91052d
              3745efe
              9216b0f
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|  | @@ -151,15 +151,12 @@ public IReadOnlyList<string> Fingerprint | |||
| /// <inheritdoc /> | ||||
| public IReadOnlyCollection<Breadcrumb> Breadcrumbs => _breadcrumbs; | ||||
|  | ||||
| private readonly ConcurrentDictionary<string, object?> _data = new(); | ||||
|  | ||||
| /// <inheritdoc /> | ||||
| [Obsolete("Use Data")] | ||||
| public IReadOnlyDictionary<string, object?> Extra => _data; | ||||
| public IReadOnlyDictionary<string, object?> Extra => _contexts.Trace.Data; | ||||
|  | ||||
| /// <inheritdoc /> | ||||
| public IReadOnlyDictionary<string, object?> Data => _data; | ||||
|  | ||||
| public IReadOnlyDictionary<string, object?> Data => _contexts.Trace.Data; | ||||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||||
|  | ||||
| private readonly ConcurrentDictionary<string, string> _tags = new(); | ||||
|  | ||||
|  | @@ -270,10 +267,10 @@ internal TransactionTracer(IHub hub, ITransactionContext context, TimeSpan? idle | |||
|  | ||||
| /// <inheritdoc /> | ||||
| [Obsolete("Use SetData")] | ||||
| public void SetExtra(string key, object? value) => _data[key] = value; | ||||
| public void SetExtra(string key, object? value) => _contexts.Trace.SetData(key, value); | ||||
|  | ||||
| /// <inheritdoc /> | ||||
| public void SetData(string key, object? value) => _data[key] = value; | ||||
| public void SetData(string key, object? value) => _contexts.Trace.SetData(key, value); | ||||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question: concurrency The now used 
 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) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 
 The TransactionTracer is potentially accessed concurrently (we set it onto the Scope which has concurrent access in both global mode (every  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. | ||||
|  | ||||
| /// <inheritdoc /> | ||||
| public void SetTag(string key, string value) => _tags[key] = value; | ||||
|  | ||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|  | @@ -22,7 +22,11 @@ | |||||
| Origin: auto.http.aspnetcore, | ||||||
| Description: , | ||||||
| Status: Ok, | ||||||
| IsSampled: true | ||||||
| IsSampled: true, | ||||||
| Data: { | ||||||
| http.request.method: GET, | ||||||
| http.response.status_code: 200 | ||||||
| } | ||||||
| 
      Comment on lines
    
      +26
     to 
      +29
    
   There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. note: from 
 | ||||||
| } | ||||||
| }, | ||||||
| User: { | ||||||
|  | @@ -80,7 +84,11 @@ | |||||
| route.controller: Version, | ||||||
| route.version: 1.1 | ||||||
| }, | ||||||
| IsFinished: true | ||||||
| IsFinished: true, | ||||||
| Data: { | ||||||
| http.request.method: GET, | ||||||
| http.response.status_code: 200 | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| ] | ||||||
|  | ||||||
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|  | @@ -258,7 +258,7 @@ public void SerializeObject_AllPropertiesSetToNonDefault_SerializesValidObject() | |||
|  | ||||
| // Act | ||||
| var finalTransaction = new SentryTransaction(transaction); | ||||
| var actualString = finalTransaction.ToJsonString(_testOutputLogger); | ||||
| var actualString = finalTransaction.ToJsonString(_testOutputLogger, indented: true); | ||||
| var actual = Json.Parse(actualString, SentryTransaction.FromJson); | ||||
|  | ||||
| // Assert | ||||
|  | @@ -278,6 +278,30 @@ public void SerializeObject_AllPropertiesSetToNonDefault_SerializesValidObject() | |||
|  | ||||
| return o; | ||||
| }); | ||||
|  | ||||
| Assert.Contains($$""" | ||||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. note: I kept this test similar to 
 which also does a serialize/deserialize-roundtrip test plus an additional "Contains-JSON" check on the serialized string | ||||
| "contexts": { | ||||
| ".NET Framework": { | ||||
| ".NET Framework": "\u0022v2.0.50727\u0022, \u0022v3.0\u0022, \u0022v3.5\u0022", | ||||
| ".NET Framework Client": "\u0022v4.8\u0022, \u0022v4.0.0.0\u0022", | ||||
| ".NET Framework Full": "\u0022v4.8\u0022" | ||||
| }, | ||||
| "context_key": "context_value", | ||||
| "trace": { | ||||
| "type": "trace", | ||||
| "span_id": "{{context.SpanId}}", | ||||
| "parent_span_id": "{{context.ParentSpanId}}", | ||||
| "trace_id": "{{context.TraceId}}", | ||||
| "op": "op123", | ||||
| "origin": "auto.serialize.transaction", | ||||
| "description": "desc123", | ||||
| "status": "aborted", | ||||
| "data": { | ||||
| "extra_key": "extra_value" | ||||
| } | ||||
| } | ||||
| } | ||||
| """, actualString); | ||||
| } | ||||
|  | ||||
| [Fact] | ||||
|  | ||||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: reference Contexts in
SentryTransactionvs copy Contexts toSentryTransactionWhen creating a
SentryTransactionfromITransactionTracer, we reference theSentryContexts:sentry-dotnet/src/Sentry/SentryTransaction.cs
Line 246 in 3745efe
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
SetDatawriting intoSentryContexts.Trace.Datadirectly, instead when creating theSentryTransactionfrom theITransactionTracercopy theITransactionTracer.Data(backed by it's ownDictionary`2) over to the Context of the newSentryTransaction.E.g. something like
or similar.
But that would have a side-effect on the
ContextsofTransactionTracer, which I don't think is expected when creating a newSentryTransactionfromTransactionTracer.Should we perhaps indeed make a copy of the
Traceand/orSentryContext?Relates to #3936 (comment)