-
-
Notifications
You must be signed in to change notification settings - Fork 230
feat: Add W3C traceparent support to tracing client and utils #4084
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
Merged
jamescrosswell
merged 24 commits into
getsentry:main
from
hangy:3069-traceparent-header
Apr 14, 2025
Merged
Changes from all commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
9735bfc
feat: Send W3C traceparent using `SentryMessageHandler`
hangy 0954802
docs: Update documentation to include 'traceparent' in HTTP header pr…
hangy d05d9c9
test: Refactor Sentry trace header tests to use parameterized inputs
hangy d572cef
fix: Typo
hangy 23b3d52
refactor: Make SentryTraceHeaderExtensions internal
hangy e36a636
refactor: Move W3C header related stuff to dedicated `W3CTraceHeader`…
hangy cffea5c
refactor: Update W3CTraceHeader to improve parsing and error handling
hangy 4818a25
feat: Implement TryGetW3CTraceHeader in Middlewares and Extensions
hangy f14cad5
refactor: Convert Sentry header tests to use [Theory] with InlineData…
hangy 108a0fc
fix: traceparent's `trace-flags` are mandatory
hangy 5c510a4
docs: Add changelog entry for traceparent header support in HTTP requ…
hangy 8cf3195
test: Improve code coverage of `W3CTraceHeader` class
hangy 66e4d5a
Merge branch 'main' into 3069-traceparent-header
jamescrosswell 4d86280
docs: Document the priority of sentry-trace and traceparent headers
hangy f3cd9c7
test: Use `HeaderName` contstant to refer to HTTP tracing headers
hangy dc5c2cf
feat: Update W3C trace header parsing to support additional sampled flag
hangy cc4b563
test: Add additional test case for Sentry trace header parsing
hangy 9c56dbb
chore: Remove redundant tests
hangy 44c0d98
test: Add test to ensure that `sentry-trace` and `traceparent` header…
hangy 358e1da
test: Enhance W3C trace header parsing tests to handle invalid trace …
hangy cb91a92
refactor: Move trace flags constants to public access in W3CTraceHead…
hangy 5ced28c
Merge branch 'main' into pr/4084
jamescrosswell 733544c
Update CHANGELOG.md
jamescrosswell a6209ee
Merge branch 'main' into 3069-traceparent-header
hangy File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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,131 @@ | ||
| namespace Sentry; | ||
|
|
||
| /// <summary> | ||
| /// Extension methods for working with Sentry trace headers. | ||
| /// </summary> | ||
| internal class W3CTraceHeader | ||
| { | ||
| private const string SupportedVersion = "00"; | ||
|
|
||
| /// <summary> | ||
| /// The name of the W3C trace context header used for distributed tracing. | ||
| /// This field contains the value "traceparent" which is part of the W3C Trace Context specification. | ||
| /// </summary> | ||
| public const string HttpHeaderName = "traceparent"; | ||
|
|
||
| /// <summary> | ||
| /// Represents the sampled trace flags value ("01") in W3C Trace Context specification. | ||
| /// This flag indicates that the trace is part of the sampling set and should be recorded. | ||
| /// </summary> | ||
| public const string TraceFlagsSampled = "01"; | ||
|
|
||
| /// <summary> | ||
| /// Represents the unsampled trace flags value ("00") in W3C Trace Context specification. | ||
| /// This flag indicates that the trace is not part of the sampling set and should not be recorded. | ||
| /// </summary> | ||
| public const string TraceFlagsNotSampled = "00"; | ||
|
|
||
| /// <summary> | ||
| /// Initializes a new instance of the <see cref="W3CTraceHeader"/> class from a Sentry trace header. | ||
| /// </summary> | ||
| /// <param name="source">The source Sentry trace header to create the W3C trace header from.</param> | ||
| /// <exception cref="ArgumentNullException">Thrown when <paramref name="source"/> is null.</exception> | ||
| public W3CTraceHeader(SentryTraceHeader source) | ||
| { | ||
| if (source is null) | ||
| { | ||
| throw new ArgumentNullException(nameof(source), "Source Sentry trace header cannot be null."); | ||
| } | ||
|
|
||
| SentryTraceHeader = source; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Gets the Sentry trace header containing trace identification and sampling information. | ||
| /// </summary> | ||
| /// <value> | ||
| /// The Sentry trace header that contains the trace ID, span ID, and sampling decision. | ||
| /// </value> | ||
| public SentryTraceHeader SentryTraceHeader { get; } | ||
|
|
||
| /// <summary> | ||
| /// Parses a <see cref="SentryTraceHeader"/> from a string representation of the Sentry trace header. | ||
| /// </summary> | ||
| /// <param name="value"> | ||
| /// A string containing the Sentry trace header, expected to follow the format "traceId-spanId-sampled", | ||
| /// where "sampled" is optional. | ||
| /// </param> | ||
| /// <returns> | ||
| /// A <see cref="SentryTraceHeader"/> object if parsing succeeds, or <c>null</c> if the input string is null, empty, or whitespace. | ||
| /// </returns> | ||
| /// <exception cref="FormatException"> | ||
| /// Thrown if the input string does not contain a valid trace header format, specifically if it lacks required trace ID and span ID components. | ||
| /// </exception> | ||
| public static W3CTraceHeader? Parse(string value) | ||
| { | ||
| if (string.IsNullOrWhiteSpace(value)) | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| var components = value.Split('-', StringSplitOptions.RemoveEmptyEntries); | ||
| if (components.Length < 4) | ||
| { | ||
| throw new FormatException($"Invalid W3C trace header: {value}."); | ||
| } | ||
|
|
||
| var version = components[0]; | ||
| if (version != SupportedVersion) | ||
| { | ||
| throw new FormatException($"Invalid W3C trace header version: {version}."); | ||
| } | ||
|
|
||
| var traceId = SentryId.Parse(components[1]); | ||
| var spanId = SpanId.Parse(components[2]); | ||
| var isSampled = ConvertTraceFlagsToSampled(components[3]); | ||
|
|
||
| return new W3CTraceHeader(new SentryTraceHeader(traceId, spanId, isSampled)); | ||
| } | ||
|
|
||
| /// <inheritdoc/> | ||
| public override string ToString() | ||
| { | ||
| var traceFlags = ConvertSampledToTraceFlags(SentryTraceHeader.IsSampled); | ||
| return $"{SupportedVersion}-{SentryTraceHeader.TraceId}-{SentryTraceHeader.SpanId}-{traceFlags}"; | ||
| } | ||
|
|
||
| private static string? ConvertSampledToTraceFlags(bool? isSampled) => (isSampled ?? false) ? TraceFlagsSampled : TraceFlagsNotSampled; | ||
|
|
||
| private static bool? ConvertTraceFlagsToSampled(string? traceFlags) | ||
| { | ||
| if (string.IsNullOrWhiteSpace(traceFlags) || traceFlags.Length != 2) | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| // In version 00 of the W3C Trace Context specification, the trace flags field is 2 hex digits. | ||
| // Only the first bit is used. We use string comparison first to avoid parsing the hex value in | ||
| // the bulk of all cases. | ||
| // See https://github.com/getsentry/sentry-dotnet/pull/4084#discussion_r2035771628 | ||
| if (string.Equals(traceFlags, TraceFlagsSampled, StringComparison.Ordinal)) | ||
| { | ||
| return true; | ||
| } | ||
| else if (string.Equals(traceFlags, TraceFlagsNotSampled, StringComparison.Ordinal)) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| // If the trace flags field is not "01" or "00", we try to parse it as a hex number. | ||
| // This is a fallback for cases where the trace flags field is not in the expected format. | ||
| if (!byte.TryParse(traceFlags, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out byte traceFlagsBytes)) | ||
| { | ||
| // If it's not a valid hex number, we can't parse it. | ||
| return null; | ||
| } | ||
|
|
||
| // The first bit of the trace flags field indicates whether the trace is sampled. | ||
| // We use bitwise AND to check if the first bit is set. | ||
| return (traceFlagsBytes & 0x01) == 1; | ||
| } | ||
| } |
This file contains hidden or 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
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.