Skip to content

Log GraphQL requests at trace level for replay - #27004

Merged
evan-wall-mysten merged 1 commit into
mainfrom
evan-wall-mysten/graphql-capture-requests
Jun 22, 2026
Merged

Log GraphQL requests at trace level for replay#27004
evan-wall-mysten merged 1 commit into
mainfrom
evan-wall-mysten/graphql-capture-requests

Conversation

@evan-wall-mysten

@evan-wall-mysten evan-wall-mysten commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

Description

Captures GraphQL requests so they can be replayed later. Each request's verbatim payload (query, variables, operationName) is logged on the graphql_request tracing target at trace level, with the operation kind recorded on the enclosing span.

Disabled by default. Capture all kinds with RUST_LOG=graphql_request=trace, or a single kind with an EnvFilter span-field directive, e.g. RUST_LOG="graphql_request[{kind=mutation}]=trace" (add RUST_LOG_JSON=1 / RUST_LOG_FILE for newline-delimited JSON). Capture reuses the document parsed during normal request execution, so it never re-parses the query and stays a no-op when disabled.

Test plan

New unit tests assert that a span-field directive captures only the configured operation kind, that graphql_request=trace captures all kinds, and that capture is off by default.


Release notes

Check each box that your changes affect. If none of the boxes relate to your changes, release notes aren't required.

For each box you select, include information after the relevant heading that describes the impact of your changes that a user might notice and any actions they must take to implement updates.

  • Protocol:
  • Nodes (Validators and Full nodes):
  • gRPC:
  • JSON-RPC:
  • GraphQL: GraphQL request payloads can be captured for replay by enabling the graphql_request tracing target at trace level — all kinds via RUST_LOG=graphql_request=trace, or a single operation kind via RUST_LOG="graphql_request[{kind=mutation}]=trace". Disabled by default.
  • CLI:
  • Rust SDK:
  • Indexing Framework:

@vercel

vercel Bot commented Jun 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
sui-docs Ready Ready Preview, Comment Jun 22, 2026 3:28pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
multisig-toolkit Ignored Ignored Preview Jun 22, 2026 3:28pm
sui-kiosk Ignored Ignored Preview Jun 22, 2026 3:28pm

Request Review

@evan-wall-mysten
evan-wall-mysten temporarily deployed to sui-typescript-aws-kms-test-env June 18, 2026 15:06 — with GitHub Actions Inactive
@evan-wall-mysten
evan-wall-mysten marked this pull request as ready for review June 18, 2026 15:10
@evan-wall-mysten
evan-wall-mysten requested a review from a team as a code owner June 18, 2026 15:10
@evan-wall-mysten
evan-wall-mysten temporarily deployed to sui-typescript-aws-kms-test-env June 18, 2026 15:10 — with GitHub Actions Inactive

@amnn amnn left a 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.

I would personally not use configs for this. Instead I would use the trace! log level so that we could enable this using the RUST_LOG environment variable (you can even enable the logging for a particular operation type if the type is included in the label).

Just less boilerplate for passing this kind of config through, and more consistent with how we manage telemetry configuration in other cases. Thoughts?

@evan-wall-mysten
evan-wall-mysten force-pushed the evan-wall-mysten/graphql-capture-requests branch from 5c11945 to e925afe Compare June 18, 2026 18:26
@evan-wall-mysten
evan-wall-mysten temporarily deployed to sui-typescript-aws-kms-test-env June 18, 2026 18:26 — with GitHub Actions Inactive
@evan-wall-mysten evan-wall-mysten changed the title Add capture-requests config to log GraphQL requests for replay Log GraphQL requests at trace level for replay Jun 18, 2026
@evan-wall-mysten

Copy link
Copy Markdown
Collaborator Author

I would personally not use configs for this. Instead I would use the trace! log level so that we could enable this using the RUST_LOG environment variable (you can even enable the logging for a particular operation type if the type is included in the label).

Just less boilerplate for passing this kind of config through, and more consistent with how we manage telemetry configuration in other cases. Thoughts?

I'm not sure it is possible to filter on a log label using RUST_LOG? The closest thing I could figure out how to do is to wrap the log in a span and add a label to the span which still allowed me to do it without adding an extra config field.

Let me know if this is what you were looking for or if there is a way to filter on a log label itself.

@amnn amnn left a 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.

Yep, this looks good, thanks @evan-wall-mysten . I had a question about potentially avoiding the re-parse but seeing as this is not a cost we will pay often, it's fine if that's not easily avoidable.

/// `mutation`, or `subscription`), selecting by operation name for multi-operation documents.
/// Returns `None` if the query fails to parse or the operation cannot be resolved.
fn operation_kind(request: &Request) -> Option<&'static str> {
let doc = parse_query(&request.query).ok()?;

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.

It's a bit unfortunate that we are parsing the whole request again just for this information -- can we move where the request is captured so that we can take advantage of the already parsed request?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Done. This also prevents capure_request from needing to be called by each GraphQL handler.

Each request's verbatim payload (query, variables, operationName) is logged on the graphql_request tracing target at trace level so it can be replayed later, with the operation kind on the enclosing span. Disabled by default; capture all kinds with RUST_LOG=graphql_request=trace, or one kind with graphql_request[{kind=mutation}]=trace.

Capture happens once in the shared logging extension (LoggingExt::parse_query), covering both the POST and subscription paths, and reuses the document the framework already parsed during execution rather than re-parsing the query. The operation kind is derived lazily inside the trace-span field, so the default path (trace disabled) stays a no-op. Unparseable requests are still captured verbatim with kind "unknown".
@evan-wall-mysten
evan-wall-mysten force-pushed the evan-wall-mysten/graphql-capture-requests branch from 4602420 to 187e103 Compare June 22, 2026 15:26
@evan-wall-mysten
evan-wall-mysten temporarily deployed to sui-typescript-aws-kms-test-env June 22, 2026 15:26 — with GitHub Actions Inactive
@evan-wall-mysten
evan-wall-mysten merged commit cf37117 into main Jun 22, 2026
63 checks passed
@evan-wall-mysten
evan-wall-mysten deleted the evan-wall-mysten/graphql-capture-requests branch June 22, 2026 16:09
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.

2 participants