Log GraphQL requests at trace level for replay - #27004
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
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?
5c11945 to
e925afe
Compare
I'm not sure it is possible to filter on a log label using Let me know if this is what you were looking for or if there is a way to filter on a log label itself. |
e925afe to
8896d27
Compare
amnn
left a comment
There was a problem hiding this comment.
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()?; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Done. This also prevents capure_request from needing to be called by each GraphQL handler.
daddfc3 to
4602420
Compare
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".
4602420 to
187e103
Compare
Description
Captures GraphQL requests so they can be replayed later. Each request's verbatim payload (query, variables, operationName) is logged on the
graphql_requesttracing target attracelevel, 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 anEnvFilterspan-field directive, e.g.RUST_LOG="graphql_request[{kind=mutation}]=trace"(addRUST_LOG_JSON=1/RUST_LOG_FILEfor 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=tracecaptures 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.
graphql_requesttracing target at trace level — all kinds viaRUST_LOG=graphql_request=trace, or a single operation kind viaRUST_LOG="graphql_request[{kind=mutation}]=trace". Disabled by default.