Skip to content

feat: Add opt-in SQLCommenter W3C trace context propagation (fixes #6255) - #6664

Open
cloudsealed wants to merge 5 commits into
npgsql:mainfrom
cloudsealed:feature/issue-6255-sqlcommenter-tracing
Open

cloudsealed wants to merge 5 commits into
npgsql:mainfrom
cloudsealed:feature/issue-6255-sqlcommenter-tracing

Conversation

@cloudsealed

Copy link
Copy Markdown

Fixes #6255.

Description

This PR adds opt-in support for W3C SQLCommenter trace context propagation in Npgsql, as discussed in #6255.

When enabled via EnableSqlCommenterTracePropagation(), Npgsql appends the W3C traceparent context as a SQL comment (/*traceparent='...'*/) to outgoing queries when an active Activity.Current is present.

Key Changes

  1. Added EnableSqlCommenterTracePropagation() opt-in method to NpgsqlTracingOptionsBuilder.
  2. Added AppendSqlCommenterTraceContext formatter to NpgsqlActivitySource.
  3. Injected SQLCommenter context into commands during trace execution in NpgsqlCommand.cs.
  4. Registered public API method in src/Npgsql/PublicAPI.Unshipped.txt.
  5. Added unit test SqlCommenterTracePropagation in TracingTests.cs.

Performance Impact

Default configuration (EnableSqlCommenterTracePropagation = false) incurs zero allocation and zero overhead on the hot path.

Comment thread src/Npgsql/NpgsqlActivitySource.cs Outdated
var traceparent = $"00-{activity.TraceId}-{activity.SpanId}-{(activity.Recorded ? "01" : "00")}";
var comment = $"/*traceparent='{traceparent}'*/";

return commandText.EndsWith(";")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
return commandText.EndsWith(";")
return commandText.EndsWith(';')

use the char-overload.

Comment thread src/Npgsql/NpgsqlActivitySource.cs Outdated
var comment = $"/*traceparent='{traceparent}'*/";

return commandText.EndsWith(";")
? commandText.Substring(0, commandText.Length - 1) + " " + comment + ";"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reduce allocations:

Suggested change
? commandText.Substring(0, commandText.Length - 1) + " " + comment + ";"
? $"{commandText.AsSpan(0, commandText.Length - 1)} {comment};"

…ests

Only append the traceparent comment to unprepared statements. Prepared
statements only send Bind (the comment never reached the server) and their
FinalCommandText is not regenerated, so the comment accumulated on every
execution. Statements being prepared would also bake a stale traceparent
into the server-side prepared statement.

Tests now assert the exact SQL received by the server via current_query().
Expand the XML docs of EnableSqlCommenterTracePropagation to explain that the
traceparent makes the SQL text unique per execution (incompatible with
server-side statement caching, see npgsql#6255 and google/sqlcommenter#284), that
prepared/auto-prepared statements are never modified, and that the feature is
experimental. Add a test for commands with multiple statements.
Covers the Recorded ? "01" : "00" branch in AppendSqlCommenterTraceContext,
which no existing test exercised (all prior tests assumed a sampled activity).
@cloudsealed

Copy link
Copy Markdown
Author

Thanks @gfoidl! Applied both suggestions in 41a119b. While adding integration tests that assert on current_query(), I also found that the comment was being appended to prepared statements (accumulating on every execution, and baking a stale traceparent into auto-prepared statements). Fixed in fa3d9e4, with tests covering explicit and auto-prepare, plus one more covering the unsampled-trace flag.

This branch has not been deployed

No deployments
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.

Support OpenTelemetry context propagation for database traces

2 participants