Skip to content

feat(router): logger improvements, access logs - #1283

Merged
dotansimha merged 27 commits into
mainfrom
minilog
Jul 26, 2026
Merged

feat(router): logger improvements, access logs #1283
dotansimha merged 27 commits into
mainfrom
minilog

Conversation

@dotansimha

@dotansimha dotansimha commented Jul 15, 2026

Copy link
Copy Markdown
Member

Closes #755
Closes #765
Closes #503

Docs PR: graphql-hive/docs#147
Docs preview: https://a507d5b7-hive-platform-docs.theguild.workers.dev/graphql/hive/docs/router/observability/logging

Background

Extracted only the crucial changes from #775 and re-implements major parts of it.

Changes in this PR

Disable logging from internal crates

A new config flag log.log_internals (default: false) has been added, that creates a Targets filter. It has a hardcoded list of log targets (mostly ntex) to remove and avoid printing. Most of ntex internal logging are noise, and we would like to avoid logging it, even when debug level is set.

A user can enable these by setting log.log_internals=true, or by setting LOG_INTERNALS=true in the env.

Improved existing log lines

This PR also iterated all of the existing log lines (specifically the debug/info/warn/error levels) and adjusted the following:

  • User-based errors (like validation/parsing/invalid requests) are logged as warning, as they do not imply a router error.
  • Router-based/internal-errors (like failure to load schema or apply an internal process in the pipeline) are printed as errors level.
  • All log lines have target configured explicitly, so log lines are now much more clear and easy to read or filter.
  • Everything related to the router workflow/pipeline is printed as debug. No log lines are printed on the hotpath, expect for the summary (see below).
  • No nested fields or nested structued are printed, to allow log ingestors to process logs easily.
  • Added new log lines in decision areas of the Router, all under DEBUG level.

Structured Logging

I've iterated all existing log lines and modified their attributes to be printed as-is, instead of printing it using a raw string. This allow JSON logging to be printed nicely and inspected by tools like DataDog or Grafana.

The message of each log line is only there to indicate and identify the even, and no log message contains information about the event. All data and fields are tracked as standalone fields, and they are not nested.

Performance impact

tracing crate internal processes can be heavy. To avoid a major perf regression, while still allowing usersto get meaningful logs that are all-or-nothing, we've implement several mechanism and applied decisions to find the right balance:

  • We do not use tracing's internal request-id correlation mechanism that is based on spans - this has a major impact since it records too many data items. Instead, we have a task-local implementation that tracks exactly what we need.
  • Custom logs formatters are in charge of correlation the log line with the request.
  • JSON log formatter is implemented from scratch, without performing any serialization (no serde / sonic_rs or any other itermediate representation).
  • The default log level is INFO and it prints only the request summary (see below), everything else is DEBUG.
  • All log lines that are lower than DEBUG in our code ( = TRACE) are dropped at compile time.

Custom log formatters

For json logging, we've implemented a custom formatter that does not construct any object, and avoid any JSON object allocations, or serialization. This means, that we construct the JSON output log lines, with a simple buffer that's also shared to avoid re-allocation for every log line.

For text logging, we use the compact format, but avoid re-allocation of new objects when possible.

The new, custom, log formatters are also in charge of injecting the request identifiers into every log line.

Access Logs / Request Summary

While running the request, we attached a RequestSummary object that has a set of pre-defined attributes that are relevant for a request summary:

pub struct RequestSummary {
    pub client_name: OnceLock<String>,
    pub client_version: OnceLock<String>,
    pub operation_name: OnceLock<String>,
    pub operation_type: OnceLock<&'static str>,
    pub operation_hash: OnceLock<String>,
    pub persisted_document_id: OnceLock<String>,
    pub subgraph_requests: AtomicU32,
    pub involved_subgraphs: Mutex<HashSet<String>>,
    pub error_count: AtomicU32,
    pub partial_response: AtomicBool,
    pub response_code: OnceLock<&'static str>,
    pub response_mode: OnceLock<&'static str>,
    pub status_code: AtomicU16,
    pub payload_bytes: AtomicI64,
    pub duration_ms: AtomicU64,
}

During execution, a task-local struct is attached to the request execution, and different part of the codebase can record information and hints about the execution. I tried to avoid any allocations where possible, but we can't avoid them all due to the need to use 'static lifetime for the task-local variable.

Once a request completes, a single log line is printed on the INFO level, summarizes the request overall:

2026-07-22T06:03:46.293394Z  INFO router::request: operation_name=“IntrospectionQuery” operation_hash=“1a9246e236afb66a7cccaf18c07c38f2" subgraph_requests=0 involved_subgraphs=“” error_count=0 partial_response=false response_mode=“dual” status_code=200 payload_bytes=17302 duration_ms=3 request_id=629431863395501115

Logs Correlation

In order to implement full request correlation, every incoming request is being inspected for both request-id and traceparent information. Both can be configured, or fully disabled from the config.

log:
  correlation:
    id_header: x-request-id
    trace_propagation: true
image

In order to do that, we create a tokio task-specific variable that holds the request identifiers extracted from the request. Then the task-local data is passed to the request processing Future.

If a request doesn't have a X-Request-ID header, then Router will generate one for it, so logs lines are always correlated.

Subscriptions support

Same as HTTP, subscriptions also extract correlations and attached them, either based on the initial message headers, or based on the per-operation headers.

We do not print a log line for the initial HTTP part of Subscriptions, and we consider every operation execution on the subscriptions channel as a separate execution when it comes to requst-id correlation.

Request correlation is based on the headers that can be passed over the init message, or subscribe message.

The request-id and request-summary are being passed to the execution thread (as Arc) of subscriptions, so they can also correlate log lines and report summary details without effort.

For stream-based HTTP requests, I've implemented mechanism to "bind"/attach the summary and request-identifier to the response, so when ntex finally drops the response, it will Drop the summary object that will print the correct summary information.
Also, duration_ms for stream-based reports the final time of the request, since it was staretd. For payload_bytes it will be an accumulation of all bytes sent in all events.

Improved log filter

The existing log.log_filter (or LOG_FILTER env var) can now mute noise from the router itself, by doing something like LOG_FILTER=router::supergraph=off. This allow more granular control over specific targets and parts of the Router logs.

Non-blocking stdout logging

Instead of using the default stdout, we are now using tracing-appender's solution for non-blocking writing https://docs.rs/tracing-appender/latest/tracing_appender/#non-blocking-writer.

Also, the output is buffered so it won't print every character to the stdout immediately, to prevent over-flushing of data to the stdout.

Testing

Added some e2e to cover the important log lines, log attributes, req-id correlations, and also to test and cover the impact on OTEL (due to the "fake" span we create for the logging).

Breaking Changes

  • Log level trace no longer available
  • Log formats pretty, tree and pretty-compact no longer available, only text and json are available now.

TODO

  • apply core changes from previous PR
  • changes to code to make it more logging-friendly
  • http request logging
  • subgraph calls logging
  • graphql layer logging
  • env vars control
  • bring back env-based log filter
  • trace level in development only
  • e2e testing
  • subscriptions
  • figure out perf regression
  • subgraph call target
  • subgraph http logging
  • schema id in the log line
  • subscriptions support (correlation over spawn)
  • stream support (duration_ms + payload_bytes)
  • sonyflake?
  • changeset
  • docs

@dotansimha dotansimha changed the title logger improvements feat(router): logger improvements Jul 15, 2026

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request introduces structured logging and request correlation to the router, replacing tracing-tree with tracing-appender and implementing request ID generation and extraction via sonyflake and HTTP headers. The review feedback focuses on performance and style guide compliance, specifically recommending the use of lazy formatting for trace IDs to avoid heap allocations on the hot path, adding a descriptive error message to an expect call, removing a redundant type conversion, and avoiding an unnecessary Vec allocation when creating target filters.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread lib/internal/src/telemetry/logging/logger_span.rs Outdated
Comment thread lib/internal/src/telemetry/logging/request_id.rs
Comment thread lib/internal/src/telemetry/logging/request_id.rs
Comment thread lib/internal/src/telemetry/logging/utils.rs
@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown

🐋 This PR was built and pushed to the following Docker images:

Image Names: ghcr.io/graphql-hive/router

Platforms: linux/amd64,linux/arm64

Image Tags: ghcr.io/graphql-hive/router:pr-1283 ghcr.io/graphql-hive/router:sha-ebd2267

Docker metadata
{
"buildx.build.provenance/linux/amd64": {
  "builder": {
    "id": "https://github.com/graphql-hive/router/actions/runs/30208149531/attempts/1"
  },
  "buildType": "https://mobyproject.org/buildkit@v1",
  "materials": [
    {
      "uri": "pkg:docker/docker/dockerfile@1.22",
      "digest": {
        "sha256": "4a43a54dd1fedceb30ba47e76cfcf2b47304f4161c0caeac2db1c61804ea3c91"
      }
    },
    {
      "uri": "pkg:docker/gcr.io/distroless/cc-debian12@latest?platform=linux%2Famd64",
      "digest": {
        "sha256": "e8e7ee4b8b106d4c5fde9e422a321b2b8a2d5cca546c97adcce927f3e1d36e36"
      }
    }
  ],
  "invocation": {
    "configSource": {
      "entryPoint": "router.Dockerfile"
    },
    "parameters": {
      "frontend": "gateway.v0",
      "args": {
        "cmdline": "docker/dockerfile:1.22",
        "label:org.opencontainers.image.created": "2026-07-26T15:35:32.474Z",
        "label:org.opencontainers.image.description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
        "label:org.opencontainers.image.licenses": "MIT",
        "label:org.opencontainers.image.revision": "ebd2267e07f094d8ffff141a2466714f698bb062",
        "label:org.opencontainers.image.source": "https://github.com/graphql-hive/router",
        "label:org.opencontainers.image.title": "router",
        "label:org.opencontainers.image.url": "https://github.com/graphql-hive/router",
        "label:org.opencontainers.image.vendor": "theguild",
        "label:org.opencontainers.image.version": "pr-1283",
        "source": "docker/dockerfile:1.22"
      },
      "locals": [
        {
          "name": "context"
        },
        {
          "name": "dockerfile"
        }
      ],
      "root": {
        "configSource": {
          "path": "router.Dockerfile"
        },
        "request": {
          "args": {
            "label:org.opencontainers.image.created": "2026-07-26T15:35:32.474Z",
            "label:org.opencontainers.image.description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
            "label:org.opencontainers.image.licenses": "MIT",
            "label:org.opencontainers.image.revision": "ebd2267e07f094d8ffff141a2466714f698bb062",
            "label:org.opencontainers.image.source": "https://github.com/graphql-hive/router",
            "label:org.opencontainers.image.title": "router",
            "label:org.opencontainers.image.url": "https://github.com/graphql-hive/router",
            "label:org.opencontainers.image.vendor": "theguild",
            "label:org.opencontainers.image.version": "pr-1283",
            "vcs:localdir:context": ".",
            "vcs:localdir:dockerfile": "docker",
            "vcs:revision": "ebd2267e07f094d8ffff141a2466714f698bb062",
            "vcs:source": "https://github.com/graphql-hive/router"
          }
        }
      },
      "compatibilityVersion": 30
    },
    "environment": {
      "github_actor": "dotansimha",
      "github_actor_id": "3680083",
      "github_event_name": "pull_request",
      "github_event_payload": {
        "action": "synchronize",
        "after": "bf21c72004395639f5d1b19a60b1fc2d419d27f2",
        "before": "e3323c1d8f3705c27d91e1cd743d78e048ee5dd0",
        "enterprise": {
          "avatar_url": "https://avatars.githubusercontent.com/b/187753?v=4",
          "created_at": "2024-07-02T08:52:28Z",
          "description": "",
          "html_url": "https://github.com/enterprises/the-guild",
          "id": 187753,
          "name": "The Guild",
          "node_id": "E_kgDOAALdaQ",
          "slug": "the-guild",
          "updated_at": "2026-07-11T07:16:45Z",
          "website_url": "https://the-guild.dev/"
        },
        "number": 1283,
        "organization": {
          "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
          "description": "Schema registry, analytics and gateway for GraphQL federation and other GraphQL APIs.",
          "events_url": "https://api.github.com/orgs/graphql-hive/events",
          "hooks_url": "https://api.github.com/orgs/graphql-hive/hooks",
          "id": 182742256,
          "issues_url": "https://api.github.com/orgs/graphql-hive/issues",
          "login": "graphql-hive",
          "members_url": "https://api.github.com/orgs/graphql-hive/members{/member}",
          "node_id": "O_kgDOCuRs8A",
          "public_members_url": "https://api.github.com/orgs/graphql-hive/public_members{/member}",
          "repos_url": "https://api.github.com/orgs/graphql-hive/repos",
          "url": "https://api.github.com/orgs/graphql-hive"
        },
        "pull_request": {
          "_links": {
            "comments": {
              "href": "https://api.github.com/repos/graphql-hive/router/issues/1283/comments"
            },
            "commits": {
              "href": "https://api.github.com/repos/graphql-hive/router/pulls/1283/commits"
            },
            "html": {
              "href": "https://github.com/graphql-hive/router/pull/1283"
            },
            "issue": {
              "href": "https://api.github.com/repos/graphql-hive/router/issues/1283"
            },
            "review_comment": {
              "href": "https://api.github.com/repos/graphql-hive/router/pulls/comments{/number}"
            },
            "review_comments": {
              "href": "https://api.github.com/repos/graphql-hive/router/pulls/1283/comments"
            },
            "self": {
              "href": "https://api.github.com/repos/graphql-hive/router/pulls/1283"
            },
            "statuses": {
              "href": "https://api.github.com/repos/graphql-hive/router/statuses/bf21c72004395639f5d1b19a60b1fc2d419d27f2"
            }
          },
          "active_lock_reason": null,
          "additions": 3096,
          "assignee": null,
          "assignees": [],
          "author_association": "MEMBER",
          "auto_merge": null,
          "base": {
            "label": "graphql-hive:main",
            "ref": "main",
            "repo": {
              "allow_auto_merge": false,
              "allow_forking": true,
              "allow_merge_commit": false,
              "allow_rebase_merge": false,
              "allow_squash_merge": true,
              "allow_update_branch": true,
              "archive_url": "https://api.github.com/repos/graphql-hive/router/{archive_format}{/ref}",
              "archived": false,
              "assignees_url": "https://api.github.com/repos/graphql-hive/router/assignees{/user}",
              "blobs_url": "https://api.github.com/repos/graphql-hive/router/git/blobs{/sha}",
              "branches_url": "https://api.github.com/repos/graphql-hive/router/branches{/branch}",
              "clone_url": "https://github.com/graphql-hive/router.git",
              "collaborators_url": "https://api.github.com/repos/graphql-hive/router/collaborators{/collaborator}",
              "comments_url": "https://api.github.com/repos/graphql-hive/router/comments{/number}",
              "commits_url": "https://api.github.com/repos/graphql-hive/router/commits{/sha}",
              "compare_url": "https://api.github.com/repos/graphql-hive/router/compare/{base}...{head}",
              "contents_url": "https://api.github.com/repos/graphql-hive/router/contents/{+path}",
              "contributors_url": "https://api.github.com/repos/graphql-hive/router/contributors",
              "created_at": "2024-11-20T16:16:12Z",
              "default_branch": "main",
              "delete_branch_on_merge": true,
              "deployments_url": "https://api.github.com/repos/graphql-hive/router/deployments",
              "description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
              "disabled": false,
              "downloads_url": "https://api.github.com/repos/graphql-hive/router/downloads",
              "events_url": "https://api.github.com/repos/graphql-hive/router/events",
              "fork": false,
              "forks": 16,
              "forks_count": 16,
              "forks_url": "https://api.github.com/repos/graphql-hive/router/forks",
              "full_name": "graphql-hive/router",
              "git_commits_url": "https://api.github.com/repos/graphql-hive/router/git/commits{/sha}",
              "git_refs_url": "https://api.github.com/repos/graphql-hive/router/git/refs{/sha}",
              "git_tags_url": "https://api.github.com/repos/graphql-hive/router/git/tags{/sha}",
              "git_url": "git://github.com/graphql-hive/router.git",
              "has_discussions": false,
              "has_downloads": false,
              "has_issues": true,
              "has_pages": false,
              "has_projects": false,
              "has_pull_requests": true,
              "has_wiki": false,
              "homepage": "https://the-guild.dev/graphql/hive/docs/router",
              "hooks_url": "https://api.github.com/repos/graphql-hive/router/hooks",
              "html_url": "https://github.com/graphql-hive/router",
              "id": 891604244,
              "is_template": false,
              "issue_comment_url": "https://api.github.com/repos/graphql-hive/router/issues/comments{/number}",
              "issue_events_url": "https://api.github.com/repos/graphql-hive/router/issues/events{/number}",
              "issues_url": "https://api.github.com/repos/graphql-hive/router/issues{/number}",
              "keys_url": "https://api.github.com/repos/graphql-hive/router/keys{/key_id}",
              "labels_url": "https://api.github.com/repos/graphql-hive/router/labels{/name}",
              "language": "Rust",
              "languages_url": "https://api.github.com/repos/graphql-hive/router/languages",
              "license": {
                "key": "mit",
                "name": "MIT License",
                "node_id": "MDc6TGljZW5zZTEz",
                "spdx_id": "MIT",
                "url": "https://api.github.com/licenses/mit"
              },
              "merge_commit_message": "PR_TITLE",
              "merge_commit_title": "MERGE_MESSAGE",
              "merges_url": "https://api.github.com/repos/graphql-hive/router/merges",
              "milestones_url": "https://api.github.com/repos/graphql-hive/router/milestones{/number}",
              "mirror_url": null,
              "name": "router",
              "node_id": "R_kgDONSTNFA",
              "notifications_url": "https://api.github.com/repos/graphql-hive/router/notifications{?since,all,participating}",
              "open_issues": 63,
              "open_issues_count": 63,
              "owner": {
                "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
                "events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
                "followers_url": "https://api.github.com/users/graphql-hive/followers",
                "following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
                "gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
                "gravatar_id": "",
                "html_url": "https://github.com/graphql-hive",
                "id": 182742256,
                "login": "graphql-hive",
                "node_id": "O_kgDOCuRs8A",
                "organizations_url": "https://api.github.com/users/graphql-hive/orgs",
                "received_events_url": "https://api.github.com/users/graphql-hive/received_events",
                "repos_url": "https://api.github.com/users/graphql-hive/repos",
                "site_admin": false,
                "starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
                "subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
                "type": "Organization",
                "url": "https://api.github.com/users/graphql-hive",
                "user_view_type": "public"
              },
              "private": false,
              "pull_request_creation_policy": "all",
              "pulls_url": "https://api.github.com/repos/graphql-hive/router/pulls{/number}",
              "pushed_at": "2026-07-26T15:24:58Z",
              "releases_url": "https://api.github.com/repos/graphql-hive/router/releases{/id}",
              "size": 10515,
              "squash_merge_commit_message": "PR_BODY",
              "squash_merge_commit_title": "PR_TITLE",
              "ssh_url": "git@github.com:graphql-hive/router.git",
              "stargazers_count": 95,
              "stargazers_url": "https://api.github.com/repos/graphql-hive/router/stargazers",
              "statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/{sha}",
              "subscribers_url": "https://api.github.com/repos/graphql-hive/router/subscribers",
              "subscription_url": "https://api.github.com/repos/graphql-hive/router/subscription",
              "svn_url": "https://github.com/graphql-hive/router",
              "tags_url": "https://api.github.com/repos/graphql-hive/router/tags",
              "teams_url": "https://api.github.com/repos/graphql-hive/router/teams",
              "topics": [
                "apollo-federation",
                "federation",
                "federation-gateway",
                "graphql",
                "graphql-federation",
                "router"
              ],
              "trees_url": "https://api.github.com/repos/graphql-hive/router/git/trees{/sha}",
              "updated_at": "2026-07-26T09:14:02Z",
              "url": "https://api.github.com/repos/graphql-hive/router",
              "use_squash_pr_title_as_default": true,
              "visibility": "public",
              "watchers": 95,
              "watchers_count": 95,
              "web_commit_signoff_required": false
            },
            "sha": "13643d6165e76cf3442b9dbbf1eb365b9b523702",
            "user": {
              "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
              "events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
              "followers_url": "https://api.github.com/users/graphql-hive/followers",
              "following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
              "gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
              "gravatar_id": "",
              "html_url": "https://github.com/graphql-hive",
              "id": 182742256,
              "login": "graphql-hive",
              "node_id": "O_kgDOCuRs8A",
              "organizations_url": "https://api.github.com/users/graphql-hive/orgs",
              "received_events_url": "https://api.github.com/users/graphql-hive/received_events",
              "repos_url": "https://api.github.com/users/graphql-hive/repos",
              "site_admin": false,
              "starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
              "subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
              "type": "Organization",
              "url": "https://api.github.com/users/graphql-hive",
              "user_view_type": "public"
            }
          },
          "body": "Closes https://github.com/graphql-hive/router/issues/755 \r\nCloses https://github.com/graphql-hive/router/issues/765 \r\nCloses https://github.com/graphql-hive/router/issues/503 \r\n\r\nDocs PR: https://github.com/graphql-hive/docs/pull/147 \r\nDocs preview: https://a507d5b7-hive-platform-docs.theguild.workers.dev/graphql/hive/docs/router/observability/logging\r\n\r\n## Background \r\n\r\nExtracted only the crucial changes from https://github.com/graphql-hive/router/pull/775 and re-implements major parts of it. \r\n\r\n## Changes in this PR \r\n\r\n### Disable logging from internal crates \r\n\r\nA new config flag `log.log_internals` (default: `false`) has been added, that creates a `Targets` filter. It has a hardcoded list of log targets (mostly `ntex`) to remove and avoid printing. Most of `ntex` internal logging are noise, and we would like to avoid logging it, even when `debug` level is set. \r\n\r\nA user can enable these by setting `log.log_internals=true`, or by setting `LOG_INTERNALS=true` in the env. \r\n\r\n### Improved existing log lines \r\n\r\nThis PR also iterated all of the existing log lines (specifically the debug/info/warn/error levels) and adjusted the following:\r\n\r\n* User-based errors (like validation/parsing/invalid requests) are logged as warning, as they do not imply a router error. \r\n* Router-based/internal-errors (like failure to load schema or apply an internal process in the pipeline) are printed as errors level.\r\n* All log lines have `target` configured explicitly, so log lines are now much more clear and easy to read or filter.\r\n* Everything related to the router workflow/pipeline is printed as `debug`. No log lines are printed on the hotpath, expect for the summary (see below).\r\n* No nested `fields` or nested structued are printed, to allow log ingestors to process logs easily. \r\n* Added new log lines in decision areas of the Router, all under `DEBUG` level. \r\n\r\n### Structured Logging \r\n\r\nI've iterated all existing log lines and modified their attributes to be printed as-is, instead of printing it using a raw string. This allow JSON logging to be printed nicely and inspected by tools like DataDog or Grafana. \r\n\r\nThe `message` of each log line is only there to indicate and identify the even, and no log message contains information about the event. All data and fields are tracked as standalone fields, and they are not nested. \r\n\r\n### Performance impact \r\n\r\n`tracing` crate internal processes can be heavy. To avoid a major perf regression, while still allowing usersto get meaningful logs that are all-or-nothing, we've implement several mechanism and applied decisions to find the right balance:\r\n\r\n- We do not use `tracing`'s internal request-id correlation mechanism that is based on `span`s - this has a major impact since it records too many data items. Instead, we have a task-local implementation that tracks exactly what we need. \r\n- Custom logs formatters are in charge of correlation the log line with the request. \r\n- JSON log formatter is implemented from scratch, without performing any serialization (no serde / sonic_rs or any other itermediate representation). \r\n- The default log level is `INFO` and it prints only the request summary (see below), everything else is `DEBUG`. \r\n- All log lines that are lower than `DEBUG` in our code ( = `TRACE`) are dropped at compile time.\r\n\r\n### Custom log formatters \r\n\r\nFor `json` logging, we've implemented a custom formatter that does not construct any object, and avoid any JSON object allocations, or serialization. This means, that we construct the JSON output log lines, with a simple `buffer` that's also shared to avoid re-allocation for every log line. \r\n\r\nFor `text` logging, we use the `compact` format, but avoid re-allocation of new objects when possible.\r\n\r\nThe new, custom, log formatters are also in charge of injecting the request identifiers into every log line. \r\n\r\n### Access Logs / Request Summary\r\n\r\nWhile running the request, we attached a `RequestSummary` object that has a set of pre-defined attributes that are relevant for a request summary: \r\n\r\n```rs\r\npub struct RequestSummary {\r\n    pub client_name: OnceLock<String>,\r\n    pub client_version: OnceLock<String>,\r\n    pub operation_name: OnceLock<String>,\r\n    pub operation_type: OnceLock<&'static str>,\r\n    pub operation_hash: OnceLock<String>,\r\n    pub persisted_document_id: OnceLock<String>,\r\n    pub subgraph_requests: AtomicU32,\r\n    pub involved_subgraphs: Mutex<HashSet<String>>,\r\n    pub error_count: AtomicU32,\r\n    pub partial_response: AtomicBool,\r\n    pub response_code: OnceLock<&'static str>,\r\n    pub response_mode: OnceLock<&'static str>,\r\n    pub status_code: AtomicU16,\r\n    pub payload_bytes: AtomicI64,\r\n    pub duration_ms: AtomicU64,\r\n}\r\n```\r\n\r\nDuring execution, a task-local struct is attached to the request execution, and different part of the codebase can `record` information and hints about the execution. I tried to avoid any allocations where possible, but we can't avoid them all due to the need to use `'static` lifetime for the task-local variable. \r\n\r\nOnce a request completes, a single log line is printed on the `INFO` level, summarizes the request overall: \r\n\r\n> `2026-07-22T06:03:46.293394Z  INFO router::request: operation_name=“IntrospectionQuery” operation_hash=“1a9246e236afb66a7cccaf18c07c38f2\" subgraph_requests=0 involved_subgraphs=“” error_count=0 partial_response=false response_mode=“dual” status_code=200 payload_bytes=17302 duration_ms=3 request_id=629431863395501115` \r\n\r\n### Logs Correlation\r\n\r\nIn order to implement full request correlation, every incoming request is being inspected for both request-id and traceparent information. Both can be configured, or fully disabled from the config. \r\n\r\n```yaml\r\nlog:\r\n  correlation:\r\n    id_header: x-request-id\r\n    trace_propagation: true\r\n```\r\n\r\n<img width=\"1587\" height=\"180\" alt=\"image\" src=\"https://github.com/user-attachments/assets/0c0f5d28-f947-46ae-8b62-70990eec5c70\" />\r\n\r\nIn order to do that, we create a tokio task-specific variable that holds the request identifiers extracted from the request. Then the task-local data is passed to the request processing `Future`. \r\n\r\nIf a request doesn't have a `X-Request-ID` header, then Router will generate one for it, so logs lines are always correlated.  \r\n\r\n### Subscriptions support \r\n\r\nSame as HTTP, subscriptions also extract correlations and attached them, either based on the initial message headers, or based on the per-operation headers. \r\n\r\nWe do not print a log line for the initial HTTP part of Subscriptions, and we consider every operation execution on the subscriptions channel as a separate execution when it comes to requst-id correlation. \r\n\r\nRequest correlation is based on the headers that can be passed over the init message, or subscribe message. \r\n\r\nThe request-id and request-summary are being passed to the execution thread (as `Arc`) of subscriptions, so they can also correlate log lines and report summary details without effort.\r\n\r\nFor stream-based HTTP requests, I've implemented mechanism to \"bind\"/attach the summary and request-identifier to the response, so when `ntex` finally drops the response, it will `Drop` the summary object that will print the correct summary information. \r\nAlso, `duration_ms` for stream-based reports the final time of the request, since it was staretd. For `payload_bytes` it will be an accumulation of all bytes sent in all events. \r\n\r\n### Improved log filter\r\n\r\nThe existing `log.log_filter` (or `LOG_FILTER` env var) can now mute noise from the router itself, by doing something like `LOG_FILTER=router::supergraph=off`. This allow more granular control over specific targets and parts of the Router logs. \r\n\r\n### Non-blocking stdout logging \r\n\r\nInstead of using the default `stdout`, we are now using `tracing-appender`'s solution for non-blocking writing https://docs.rs/tracing-appender/latest/tracing_appender/#non-blocking-writer.\r\n\r\nAlso, the output is buffered so it won't print every character to the `stdout` immediately, to prevent over-flushing of data to the stdout. \r\n\r\n### Testing \r\n\r\nAdded some e2e to cover the important log lines, log attributes, req-id correlations, and also to test and cover the impact on OTEL (due to the \"fake\" span we create for the logging). \r\n\r\n## Breaking Changes \r\n\r\n* Log level `trace` no longer available \r\n* Log formats `pretty`, `tree` and `pretty-compact` no longer available, only `text` and `json` are available now.\r\n\r\n## TODO \r\n\r\n- [x] apply core changes from previous PR\r\n- [x] changes to code to make it more logging-friendly\r\n- [x] http request logging\r\n- [x] subgraph calls logging\r\n- [x] graphql layer logging\r\n- [x] env vars control \r\n- [x] bring back env-based log filter\r\n- [x] `trace` level in development only\r\n- [x] e2e testing\r\n- [x] subscriptions \r\n- [x] figure out perf regression\r\n- [x] subgraph call target \r\n- [x] subgraph http logging \r\n- [x] schema id in the log line \r\n- [x] subscriptions support (correlation over `spawn`)\r\n- [x] stream support (`duration_ms` + `payload_bytes`) \r\n- [x] sonyflake?\r\n- [x] changeset\r\n- [x] docs ",
          "changed_files": 80,
          "closed_at": null,
          "comments": 4,
          "comments_url": "https://api.github.com/repos/graphql-hive/router/issues/1283/comments",
          "commits": 27,
          "commits_url": "https://api.github.com/repos/graphql-hive/router/pulls/1283/commits",
          "created_at": "2026-07-15T18:25:59Z",
          "deletions": 820,
          "diff_url": "https://github.com/graphql-hive/router/pull/1283.diff",
          "draft": false,
          "head": {
            "label": "graphql-hive:minilog",
            "ref": "minilog",
            "repo": {
              "allow_auto_merge": false,
              "allow_forking": true,
              "allow_merge_commit": false,
              "allow_rebase_merge": false,
              "allow_squash_merge": true,
              "allow_update_branch": true,
              "archive_url": "https://api.github.com/repos/graphql-hive/router/{archive_format}{/ref}",
              "archived": false,
              "assignees_url": "https://api.github.com/repos/graphql-hive/router/assignees{/user}",
              "blobs_url": "https://api.github.com/repos/graphql-hive/router/git/blobs{/sha}",
              "branches_url": "https://api.github.com/repos/graphql-hive/router/branches{/branch}",
              "clone_url": "https://github.com/graphql-hive/router.git",
              "collaborators_url": "https://api.github.com/repos/graphql-hive/router/collaborators{/collaborator}",
              "comments_url": "https://api.github.com/repos/graphql-hive/router/comments{/number}",
              "commits_url": "https://api.github.com/repos/graphql-hive/router/commits{/sha}",
              "compare_url": "https://api.github.com/repos/graphql-hive/router/compare/{base}...{head}",
              "contents_url": "https://api.github.com/repos/graphql-hive/router/contents/{+path}",
              "contributors_url": "https://api.github.com/repos/graphql-hive/router/contributors",
              "created_at": "2024-11-20T16:16:12Z",
              "default_branch": "main",
              "delete_branch_on_merge": true,
              "deployments_url": "https://api.github.com/repos/graphql-hive/router/deployments",
              "description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
              "disabled": false,
              "downloads_url": "https://api.github.com/repos/graphql-hive/router/downloads",
              "events_url": "https://api.github.com/repos/graphql-hive/router/events",
              "fork": false,
              "forks": 16,
              "forks_count": 16,
              "forks_url": "https://api.github.com/repos/graphql-hive/router/forks",
              "full_name": "graphql-hive/router",
              "git_commits_url": "https://api.github.com/repos/graphql-hive/router/git/commits{/sha}",
              "git_refs_url": "https://api.github.com/repos/graphql-hive/router/git/refs{/sha}",
              "git_tags_url": "https://api.github.com/repos/graphql-hive/router/git/tags{/sha}",
              "git_url": "git://github.com/graphql-hive/router.git",
              "has_discussions": false,
              "has_downloads": false,
              "has_issues": true,
              "has_pages": false,
              "has_projects": false,
              "has_pull_requests": true,
              "has_wiki": false,
              "homepage": "https://the-guild.dev/graphql/hive/docs/router",
              "hooks_url": "https://api.github.com/repos/graphql-hive/router/hooks",
              "html_url": "https://github.com/graphql-hive/router",
              "id": 891604244,
              "is_template": false,
              "issue_comment_url": "https://api.github.com/repos/graphql-hive/router/issues/comments{/number}",
              "issue_events_url": "https://api.github.com/repos/graphql-hive/router/issues/events{/number}",
              "issues_url": "https://api.github.com/repos/graphql-hive/router/issues{/number}",
              "keys_url": "https://api.github.com/repos/graphql-hive/router/keys{/key_id}",
              "labels_url": "https://api.github.com/repos/graphql-hive/router/labels{/name}",
              "language": "Rust",
              "languages_url": "https://api.github.com/repos/graphql-hive/router/languages",
              "license": {
                "key": "mit",
                "name": "MIT License",
                "node_id": "MDc6TGljZW5zZTEz",
                "spdx_id": "MIT",
                "url": "https://api.github.com/licenses/mit"
              },
              "merge_commit_message": "PR_TITLE",
              "merge_commit_title": "MERGE_MESSAGE",
              "merges_url": "https://api.github.com/repos/graphql-hive/router/merges",
              "milestones_url": "https://api.github.com/repos/graphql-hive/router/milestones{/number}",
              "mirror_url": null,
              "name": "router",
              "node_id": "R_kgDONSTNFA",
              "notifications_url": "https://api.github.com/repos/graphql-hive/router/notifications{?since,all,participating}",
              "open_issues": 63,
              "open_issues_count": 63,
              "owner": {
                "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
                "events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
                "followers_url": "https://api.github.com/users/graphql-hive/followers",
                "following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
                "gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
                "gravatar_id": "",
                "html_url": "https://github.com/graphql-hive",
                "id": 182742256,
                "login": "graphql-hive",
                "node_id": "O_kgDOCuRs8A",
                "organizations_url": "https://api.github.com/users/graphql-hive/orgs",
                "received_events_url": "https://api.github.com/users/graphql-hive/received_events",
                "repos_url": "https://api.github.com/users/graphql-hive/repos",
                "site_admin": false,
                "starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
                "subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
                "type": "Organization",
                "url": "https://api.github.com/users/graphql-hive",
                "user_view_type": "public"
              },
              "private": false,
              "pull_request_creation_policy": "all",
              "pulls_url": "https://api.github.com/repos/graphql-hive/router/pulls{/number}",
              "pushed_at": "2026-07-26T15:24:58Z",
              "releases_url": "https://api.github.com/repos/graphql-hive/router/releases{/id}",
              "size": 10515,
              "squash_merge_commit_message": "PR_BODY",
              "squash_merge_commit_title": "PR_TITLE",
              "ssh_url": "git@github.com:graphql-hive/router.git",
              "stargazers_count": 95,
              "stargazers_url": "https://api.github.com/repos/graphql-hive/router/stargazers",
              "statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/{sha}",
              "subscribers_url": "https://api.github.com/repos/graphql-hive/router/subscribers",
              "subscription_url": "https://api.github.com/repos/graphql-hive/router/subscription",
              "svn_url": "https://github.com/graphql-hive/router",
              "tags_url": "https://api.github.com/repos/graphql-hive/router/tags",
              "teams_url": "https://api.github.com/repos/graphql-hive/router/teams",
              "topics": [
                "apollo-federation",
                "federation",
                "federation-gateway",
                "graphql",
                "graphql-federation",
                "router"
              ],
              "trees_url": "https://api.github.com/repos/graphql-hive/router/git/trees{/sha}",
              "updated_at": "2026-07-26T09:14:02Z",
              "url": "https://api.github.com/repos/graphql-hive/router",
              "use_squash_pr_title_as_default": true,
              "visibility": "public",
              "watchers": 95,
              "watchers_count": 95,
              "web_commit_signoff_required": false
            },
            "sha": "bf21c72004395639f5d1b19a60b1fc2d419d27f2",
            "user": {
              "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
              "events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
              "followers_url": "https://api.github.com/users/graphql-hive/followers",
              "following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
              "gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
              "gravatar_id": "",
              "html_url": "https://github.com/graphql-hive",
              "id": 182742256,
              "login": "graphql-hive",
              "node_id": "O_kgDOCuRs8A",
              "organizations_url": "https://api.github.com/users/graphql-hive/orgs",
              "received_events_url": "https://api.github.com/users/graphql-hive/received_events",
              "repos_url": "https://api.github.com/users/graphql-hive/repos",
              "site_admin": false,
              "starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
              "subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
              "type": "Organization",
              "url": "https://api.github.com/users/graphql-hive",
              "user_view_type": "public"
            }
          },
          "html_url": "https://github.com/graphql-hive/router/pull/1283",
          "id": 4062814180,
          "issue_url": "https://api.github.com/repos/graphql-hive/router/issues/1283",
          "labels": [],
          "locked": false,
          "maintainer_can_modify": false,
          "merge_commit_sha": "57391e94824b20a53535babe7cbfe7aa8e8d5d36",
          "mergeable": null,
          "mergeable_state": "unknown",
          "merged": false,
          "merged_at": null,
          "merged_by": null,
          "milestone": null,
          "node_id": "PR_kwDONSTNFM7yKZ_k",
          "number": 1283,
          "patch_url": "https://github.com/graphql-hive/router/pull/1283.patch",
          "rebaseable": null,
          "requested_reviewers": [
            {
              "avatar_url": "https://avatars.githubusercontent.com/u/8167190?v=4",
              "events_url": "https://api.github.com/users/kamilkisiela/events{/privacy}",
              "followers_url": "https://api.github.com/users/kamilkisiela/followers",
              "following_url": "https://api.github.com/users/kamilkisiela/following{/other_user}",
              "gists_url": "https://api.github.com/users/kamilkisiela/gists{/gist_id}",
              "gravatar_id": "",
              "html_url": "https://github.com/kamilkisiela",
              "id": 8167190,
              "login": "kamilkisiela",
              "node_id": "MDQ6VXNlcjgxNjcxOTA=",
              "organizations_url": "https://api.github.com/users/kamilkisiela/orgs",
              "received_events_url": "https://api.github.com/users/kamilkisiela/received_events",
              "repos_url": "https://api.github.com/users/kamilkisiela/repos",
              "site_admin": false,
              "starred_url": "https://api.github.com/users/kamilkisiela/starred{/owner}{/repo}",
              "subscriptions_url": "https://api.github.com/users/kamilkisiela/subscriptions",
              "type": "User",
              "url": "https://api.github.com/users/kamilkisiela",
              "user_view_type": "public"
            },
            {
              "avatar_url": "https://avatars.githubusercontent.com/in/946600?v=4",
              "events_url": "https://api.github.com/users/Copilot/events{/privacy}",
              "followers_url": "https://api.github.com/users/Copilot/followers",
              "following_url": "https://api.github.com/users/Copilot/following{/other_user}",
              "gists_url": "https://api.github.com/users/Copilot/gists{/gist_id}",
              "gravatar_id": "",
              "html_url": "https://github.com/apps/copilot-pull-request-reviewer",
              "id": 175728472,
              "login": "Copilot",
              "node_id": "BOT_kgDOCnlnWA",
              "organizations_url": "https://api.github.com/users/Copilot/orgs",
              "received_events_url": "https://api.github.com/users/Copilot/received_events",
              "repos_url": "https://api.github.com/users/Copilot/repos",
              "site_admin": false,
              "starred_url": "https://api.github.com/users/Copilot/starred{/owner}{/repo}",
              "subscriptions_url": "https://api.github.com/users/Copilot/subscriptions",
              "type": "Bot",
              "url": "https://api.github.com/users/Copilot",
              "user_view_type": "public"
            }
          ],
          "requested_teams": [],
          "review_comment_url": "https://api.github.com/repos/graphql-hive/router/pulls/comments{/number}",
          "review_comments": 65,
          "review_comments_url": "https://api.github.com/repos/graphql-hive/router/pulls/1283/comments",
          "state": "open",
          "statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/bf21c72004395639f5d1b19a60b1fc2d419d27f2",
          "title": "feat(router): logger improvements, access logs ",
          "updated_at": "2026-07-26T15:25:00Z",
          "url": "https://api.github.com/repos/graphql-hive/router/pulls/1283",
          "user": {
            "avatar_url": "https://avatars.githubusercontent.com/u/3680083?v=4",
            "events_url": "https://api.github.com/users/dotansimha/events{/privacy}",
            "followers_url": "https://api.github.com/users/dotansimha/followers",
            "following_url": "https://api.github.com/users/dotansimha/following{/other_user}",
            "gists_url": "https://api.github.com/users/dotansimha/gists{/gist_id}",
            "gravatar_id": "",
            "html_url": "https://github.com/dotansimha",
            "id": 3680083,
            "login": "dotansimha",
            "node_id": "MDQ6VXNlcjM2ODAwODM=",
            "organizations_url": "https://api.github.com/users/dotansimha/orgs",
            "received_events_url": "https://api.github.com/users/dotansimha/received_events",
            "repos_url": "https://api.github.com/users/dotansimha/repos",
            "site_admin": false,
            "starred_url": "https://api.github.com/users/dotansimha/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/dotansimha/subscriptions",
            "type": "User",
            "url": "https://api.github.com/users/dotansimha",
            "user_view_type": "public"
          }
        },
        "repository": {
          "allow_forking": true,
          "archive_url": "https://api.github.com/repos/graphql-hive/router/{archive_format}{/ref}",
          "archived": false,
          "assignees_url": "https://api.github.com/repos/graphql-hive/router/assignees{/user}",
          "blobs_url": "https://api.github.com/repos/graphql-hive/router/git/blobs{/sha}",
          "branches_url": "https://api.github.com/repos/graphql-hive/router/branches{/branch}",
          "clone_url": "https://github.com/graphql-hive/router.git",
          "collaborators_url": "https://api.github.com/repos/graphql-hive/router/collaborators{/collaborator}",
          "comments_url": "https://api.github.com/repos/graphql-hive/router/comments{/number}",
          "commits_url": "https://api.github.com/repos/graphql-hive/router/commits{/sha}",
          "compare_url": "https://api.github.com/repos/graphql-hive/router/compare/{base}...{head}",
          "contents_url": "https://api.github.com/repos/graphql-hive/router/contents/{+path}",
          "contributors_url": "https://api.github.com/repos/graphql-hive/router/contributors",
          "created_at": "2024-11-20T16:16:12Z",
          "custom_properties": {
            "vanta_production_branch_name": "main"
          },
          "default_branch": "main",
          "deployments_url": "https://api.github.com/repos/graphql-hive/router/deployments",
          "description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
          "disabled": false,
          "downloads_url": "https://api.github.com/repos/graphql-hive/router/downloads",
          "events_url": "https://api.github.com/repos/graphql-hive/router/events",
          "fork": false,
          "forks": 16,
          "forks_count": 16,
          "forks_url": "https://api.github.com/repos/graphql-hive/router/forks",
          "full_name": "graphql-hive/router",
          "git_commits_url": "https://api.github.com/repos/graphql-hive/router/git/commits{/sha}",
          "git_refs_url": "https://api.github.com/repos/graphql-hive/router/git/refs{/sha}",
          "git_tags_url": "https://api.github.com/repos/graphql-hive/router/git/tags{/sha}",
          "git_url": "git://github.com/graphql-hive/router.git",
          "has_discussions": false,
          "has_downloads": false,
          "has_issues": true,
          "has_pages": false,
          "has_projects": false,
          "has_pull_requests": true,
          "has_wiki": false,
          "homepage": "https://the-guild.dev/graphql/hive/docs/router",
          "hooks_url": "https://api.github.com/repos/graphql-hive/router/hooks",
          "html_url": "https://github.com/graphql-hive/router",
          "id": 891604244,
          "is_template": false,
          "issue_comment_url": "https://api.github.com/repos/graphql-hive/router/issues/comments{/number}",
          "issue_events_url": "https://api.github.com/repos/graphql-hive/router/issues/events{/number}",
          "issues_url": "https://api.github.com/repos/graphql-hive/router/issues{/number}",
          "keys_url": "https://api.github.com/repos/graphql-hive/router/keys{/key_id}",
          "labels_url": "https://api.github.com/repos/graphql-hive/router/labels{/name}",
          "language": "Rust",
          "languages_url": "https://api.github.com/repos/graphql-hive/router/languages",
          "license": {
            "key": "mit",
            "name": "MIT License",
            "node_id": "MDc6TGljZW5zZTEz",
            "spdx_id": "MIT",
            "url": "https://api.github.com/licenses/mit"
          },
          "merges_url": "https://api.github.com/repos/graphql-hive/router/merges",
          "milestones_url": "https://api.github.com/repos/graphql-hive/router/milestones{/number}",
          "mirror_url": null,
          "name": "router",
          "node_id": "R_kgDONSTNFA",
          "notifications_url": "https://api.github.com/repos/graphql-hive/router/notifications{?since,all,participating}",
          "open_issues": 63,
          "open_issues_count": 63,
          "owner": {
            "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
            "events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
            "followers_url": "https://api.github.com/users/graphql-hive/followers",
            "following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
            "gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
            "gravatar_id": "",
            "html_url": "https://github.com/graphql-hive",
            "id": 182742256,
            "login": "graphql-hive",
            "node_id": "O_kgDOCuRs8A",
            "organizations_url": "https://api.github.com/users/graphql-hive/orgs",
            "received_events_url": "https://api.github.com/users/graphql-hive/received_events",
            "repos_url": "https://api.github.com/users/graphql-hive/repos",
            "site_admin": false,
            "starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
            "type": "Organization",
            "url": "https://api.github.com/users/graphql-hive",
            "user_view_type": "public"
          },
          "private": false,
          "pull_request_creation_policy": "all",
          "pulls_url": "https://api.github.com/repos/graphql-hive/router/pulls{/number}",
          "pushed_at": "2026-07-26T15:24:58Z",
          "releases_url": "https://api.github.com/repos/graphql-hive/router/releases{/id}",
          "size": 10515,
          "ssh_url": "git@github.com:graphql-hive/router.git",
          "stargazers_count": 95,
          "stargazers_url": "https://api.github.com/repos/graphql-hive/router/stargazers",
          "statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/{sha}",
          "subscribers_url": "https://api.github.com/repos/graphql-hive/router/subscribers",
          "subscription_url": "https://api.github.com/repos/graphql-hive/router/subscription",
          "svn_url": "https://github.com/graphql-hive/router",
          "tags_url": "https://api.github.com/repos/graphql-hive/router/tags",
          "teams_url": "https://api.github.com/repos/graphql-hive/router/teams",
          "topics": [
            "apollo-federation",
            "federation",
            "federation-gateway",
            "graphql",
            "graphql-federation",
            "router"
          ],
          "trees_url": "https://api.github.com/repos/graphql-hive/router/git/trees{/sha}",
          "updated_at": "2026-07-26T09:14:02Z",
          "url": "https://api.github.com/repos/graphql-hive/router",
          "visibility": "public",
          "watchers": 95,
          "watchers_count": 95,
          "web_commit_signoff_required": false
        },
        "sender": {
          "avatar_url": "https://avatars.githubusercontent.com/u/3680083?v=4",
          "events_url": "https://api.github.com/users/dotansimha/events{/privacy}",
          "followers_url": "https://api.github.com/users/dotansimha/followers",
          "following_url": "https://api.github.com/users/dotansimha/following{/other_user}",
          "gists_url": "https://api.github.com/users/dotansimha/gists{/gist_id}",
          "gravatar_id": "",
          "html_url": "https://github.com/dotansimha",
          "id": 3680083,
          "login": "dotansimha",
          "node_id": "MDQ6VXNlcjM2ODAwODM=",
          "organizations_url": "https://api.github.com/users/dotansimha/orgs",
          "received_events_url": "https://api.github.com/users/dotansimha/received_events",
          "repos_url": "https://api.github.com/users/dotansimha/repos",
          "site_admin": false,
          "starred_url": "https://api.github.com/users/dotansimha/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/dotansimha/subscriptions",
          "type": "User",
          "url": "https://api.github.com/users/dotansimha",
          "user_view_type": "public"
        }
      },
      "github_job": "docker",
      "github_ref": "refs/pull/1283/merge",
      "github_ref_name": "1283/merge",
      "github_ref_protected": "false",
      "github_ref_type": "branch",
      "github_repository": "graphql-hive/router",
      "github_repository_id": "891604244",
      "github_repository_owner": "graphql-hive",
      "github_repository_owner_id": "182742256",
      "github_run_attempt": "1",
      "github_run_id": "30208149531",
      "github_run_number": "4644",
      "github_runner_arch": "X64",
      "github_runner_environment": "github-hosted",
      "github_runner_image_os": "ubuntu24",
      "github_runner_image_version": "20260720.247.2",
      "github_runner_name": "GitHub Actions 1000933918",
      "github_runner_os": "Linux",
      "github_runner_tracking_id": "github_cde20512-a663-4ffd-b6e2-d12f494b3652",
      "github_server_url": "https://github.com",
      "github_triggering_actor": "dotansimha",
      "github_workflow": "build-router",
      "github_workflow_ref": "graphql-hive/router/.github/workflows/build-router.yaml@refs/pull/1283/merge",
      "github_workflow_sha": "ebd2267e07f094d8ffff141a2466714f698bb062",
      "platform": "linux/amd64"
    }
  }
},
"buildx.build.provenance/linux/arm64": {
  "builder": {
    "id": "https://github.com/graphql-hive/router/actions/runs/30208149531/attempts/1"
  },
  "buildType": "https://mobyproject.org/buildkit@v1",
  "materials": [
    {
      "uri": "pkg:docker/docker/dockerfile@1.22",
      "digest": {
        "sha256": "4a43a54dd1fedceb30ba47e76cfcf2b47304f4161c0caeac2db1c61804ea3c91"
      }
    },
    {
      "uri": "pkg:docker/gcr.io/distroless/cc-debian12@latest?platform=linux%2Farm64",
      "digest": {
        "sha256": "e8e7ee4b8b106d4c5fde9e422a321b2b8a2d5cca546c97adcce927f3e1d36e36"
      }
    }
  ],
  "invocation": {
    "configSource": {
      "entryPoint": "router.Dockerfile"
    },
    "parameters": {
      "frontend": "gateway.v0",
      "args": {
        "cmdline": "docker/dockerfile:1.22",
        "label:org.opencontainers.image.created": "2026-07-26T15:35:32.474Z",
        "label:org.opencontainers.image.description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
        "label:org.opencontainers.image.licenses": "MIT",
        "label:org.opencontainers.image.revision": "ebd2267e07f094d8ffff141a2466714f698bb062",
        "label:org.opencontainers.image.source": "https://github.com/graphql-hive/router",
        "label:org.opencontainers.image.title": "router",
        "label:org.opencontainers.image.url": "https://github.com/graphql-hive/router",
        "label:org.opencontainers.image.vendor": "theguild",
        "label:org.opencontainers.image.version": "pr-1283",
        "source": "docker/dockerfile:1.22"
      },
      "locals": [
        {
          "name": "context"
        },
        {
          "name": "dockerfile"
        }
      ],
      "root": {
        "configSource": {
          "path": "router.Dockerfile"
        },
        "request": {
          "args": {
            "label:org.opencontainers.image.created": "2026-07-26T15:35:32.474Z",
            "label:org.opencontainers.image.description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
            "label:org.opencontainers.image.licenses": "MIT",
            "label:org.opencontainers.image.revision": "ebd2267e07f094d8ffff141a2466714f698bb062",
            "label:org.opencontainers.image.source": "https://github.com/graphql-hive/router",
            "label:org.opencontainers.image.title": "router",
            "label:org.opencontainers.image.url": "https://github.com/graphql-hive/router",
            "label:org.opencontainers.image.vendor": "theguild",
            "label:org.opencontainers.image.version": "pr-1283",
            "vcs:localdir:context": ".",
            "vcs:localdir:dockerfile": "docker",
            "vcs:revision": "ebd2267e07f094d8ffff141a2466714f698bb062",
            "vcs:source": "https://github.com/graphql-hive/router"
          }
        }
      },
      "compatibilityVersion": 30
    },
    "environment": {
      "github_actor": "dotansimha",
      "github_actor_id": "3680083",
      "github_event_name": "pull_request",
      "github_event_payload": {
        "action": "synchronize",
        "after": "bf21c72004395639f5d1b19a60b1fc2d419d27f2",
        "before": "e3323c1d8f3705c27d91e1cd743d78e048ee5dd0",
        "enterprise": {
          "avatar_url": "https://avatars.githubusercontent.com/b/187753?v=4",
          "created_at": "2024-07-02T08:52:28Z",
          "description": "",
          "html_url": "https://github.com/enterprises/the-guild",
          "id": 187753,
          "name": "The Guild",
          "node_id": "E_kgDOAALdaQ",
          "slug": "the-guild",
          "updated_at": "2026-07-11T07:16:45Z",
          "website_url": "https://the-guild.dev/"
        },
        "number": 1283,
        "organization": {
          "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
          "description": "Schema registry, analytics and gateway for GraphQL federation and other GraphQL APIs.",
          "events_url": "https://api.github.com/orgs/graphql-hive/events",
          "hooks_url": "https://api.github.com/orgs/graphql-hive/hooks",
          "id": 182742256,
          "issues_url": "https://api.github.com/orgs/graphql-hive/issues",
          "login": "graphql-hive",
          "members_url": "https://api.github.com/orgs/graphql-hive/members{/member}",
          "node_id": "O_kgDOCuRs8A",
          "public_members_url": "https://api.github.com/orgs/graphql-hive/public_members{/member}",
          "repos_url": "https://api.github.com/orgs/graphql-hive/repos",
          "url": "https://api.github.com/orgs/graphql-hive"
        },
        "pull_request": {
          "_links": {
            "comments": {
              "href": "https://api.github.com/repos/graphql-hive/router/issues/1283/comments"
            },
            "commits": {
              "href": "https://api.github.com/repos/graphql-hive/router/pulls/1283/commits"
            },
            "html": {
              "href": "https://github.com/graphql-hive/router/pull/1283"
            },
            "issue": {
              "href": "https://api.github.com/repos/graphql-hive/router/issues/1283"
            },
            "review_comment": {
              "href": "https://api.github.com/repos/graphql-hive/router/pulls/comments{/number}"
            },
            "review_comments": {
              "href": "https://api.github.com/repos/graphql-hive/router/pulls/1283/comments"
            },
            "self": {
              "href": "https://api.github.com/repos/graphql-hive/router/pulls/1283"
            },
            "statuses": {
              "href": "https://api.github.com/repos/graphql-hive/router/statuses/bf21c72004395639f5d1b19a60b1fc2d419d27f2"
            }
          },
          "active_lock_reason": null,
          "additions": 3096,
          "assignee": null,
          "assignees": [],
          "author_association": "MEMBER",
          "auto_merge": null,
          "base": {
            "label": "graphql-hive:main",
            "ref": "main",
            "repo": {
              "allow_auto_merge": false,
              "allow_forking": true,
              "allow_merge_commit": false,
              "allow_rebase_merge": false,
              "allow_squash_merge": true,
              "allow_update_branch": true,
              "archive_url": "https://api.github.com/repos/graphql-hive/router/{archive_format}{/ref}",
              "archived": false,
              "assignees_url": "https://api.github.com/repos/graphql-hive/router/assignees{/user}",
              "blobs_url": "https://api.github.com/repos/graphql-hive/router/git/blobs{/sha}",
              "branches_url": "https://api.github.com/repos/graphql-hive/router/branches{/branch}",
              "clone_url": "https://github.com/graphql-hive/router.git",
              "collaborators_url": "https://api.github.com/repos/graphql-hive/router/collaborators{/collaborator}",
              "comments_url": "https://api.github.com/repos/graphql-hive/router/comments{/number}",
              "commits_url": "https://api.github.com/repos/graphql-hive/router/commits{/sha}",
              "compare_url": "https://api.github.com/repos/graphql-hive/router/compare/{base}...{head}",
              "contents_url": "https://api.github.com/repos/graphql-hive/router/contents/{+path}",
              "contributors_url": "https://api.github.com/repos/graphql-hive/router/contributors",
              "created_at": "2024-11-20T16:16:12Z",
              "default_branch": "main",
              "delete_branch_on_merge": true,
              "deployments_url": "https://api.github.com/repos/graphql-hive/router/deployments",
              "description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
              "disabled": false,
              "downloads_url": "https://api.github.com/repos/graphql-hive/router/downloads",
              "events_url": "https://api.github.com/repos/graphql-hive/router/events",
              "fork": false,
              "forks": 16,
              "forks_count": 16,
              "forks_url": "https://api.github.com/repos/graphql-hive/router/forks",
              "full_name": "graphql-hive/router",
              "git_commits_url": "https://api.github.com/repos/graphql-hive/router/git/commits{/sha}",
              "git_refs_url": "https://api.github.com/repos/graphql-hive/router/git/refs{/sha}",
              "git_tags_url": "https://api.github.com/repos/graphql-hive/router/git/tags{/sha}",
              "git_url": "git://github.com/graphql-hive/router.git",
              "has_discussions": false,
              "has_downloads": false,
              "has_issues": true,
              "has_pages": false,
              "has_projects": false,
              "has_pull_requests": true,
              "has_wiki": false,
              "homepage": "https://the-guild.dev/graphql/hive/docs/router",
              "hooks_url": "https://api.github.com/repos/graphql-hive/router/hooks",
              "html_url": "https://github.com/graphql-hive/router",
              "id": 891604244,
              "is_template": false,
              "issue_comment_url": "https://api.github.com/repos/graphql-hive/router/issues/comments{/number}",
              "issue_events_url": "https://api.github.com/repos/graphql-hive/router/issues/events{/number}",
              "issues_url": "https://api.github.com/repos/graphql-hive/router/issues{/number}",
              "keys_url": "https://api.github.com/repos/graphql-hive/router/keys{/key_id}",
              "labels_url": "https://api.github.com/repos/graphql-hive/router/labels{/name}",
              "language": "Rust",
              "languages_url": "https://api.github.com/repos/graphql-hive/router/languages",
              "license": {
                "key": "mit",
                "name": "MIT License",
                "node_id": "MDc6TGljZW5zZTEz",
                "spdx_id": "MIT",
                "url": "https://api.github.com/licenses/mit"
              },
              "merge_commit_message": "PR_TITLE",
              "merge_commit_title": "MERGE_MESSAGE",
              "merges_url": "https://api.github.com/repos/graphql-hive/router/merges",
              "milestones_url": "https://api.github.com/repos/graphql-hive/router/milestones{/number}",
              "mirror_url": null,
              "name": "router",
              "node_id": "R_kgDONSTNFA",
              "notifications_url": "https://api.github.com/repos/graphql-hive/router/notifications{?since,all,participating}",
              "open_issues": 63,
              "open_issues_count": 63,
              "owner": {
                "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
                "events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
                "followers_url": "https://api.github.com/users/graphql-hive/followers",
                "following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
                "gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
                "gravatar_id": "",
                "html_url": "https://github.com/graphql-hive",
                "id": 182742256,
                "login": "graphql-hive",
                "node_id": "O_kgDOCuRs8A",
                "organizations_url": "https://api.github.com/users/graphql-hive/orgs",
                "received_events_url": "https://api.github.com/users/graphql-hive/received_events",
                "repos_url": "https://api.github.com/users/graphql-hive/repos",
                "site_admin": false,
                "starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
                "subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
                "type": "Organization",
                "url": "https://api.github.com/users/graphql-hive",
                "user_view_type": "public"
              },
              "private": false,
              "pull_request_creation_policy": "all",
              "pulls_url": "https://api.github.com/repos/graphql-hive/router/pulls{/number}",
              "pushed_at": "2026-07-26T15:24:58Z",
              "releases_url": "https://api.github.com/repos/graphql-hive/router/releases{/id}",
              "size": 10515,
              "squash_merge_commit_message": "PR_BODY",
              "squash_merge_commit_title": "PR_TITLE",
              "ssh_url": "git@github.com:graphql-hive/router.git",
              "stargazers_count": 95,
              "stargazers_url": "https://api.github.com/repos/graphql-hive/router/stargazers",
              "statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/{sha}",
              "subscribers_url": "https://api.github.com/repos/graphql-hive/router/subscribers",
              "subscription_url": "https://api.github.com/repos/graphql-hive/router/subscription",
              "svn_url": "https://github.com/graphql-hive/router",
              "tags_url": "https://api.github.com/repos/graphql-hive/router/tags",
              "teams_url": "https://api.github.com/repos/graphql-hive/router/teams",
              "topics": [
                "apollo-federation",
                "federation",
                "federation-gateway",
                "graphql",
                "graphql-federation",
                "router"
              ],
              "trees_url": "https://api.github.com/repos/graphql-hive/router/git/trees{/sha}",
              "updated_at": "2026-07-26T09:14:02Z",
              "url": "https://api.github.com/repos/graphql-hive/router",
              "use_squash_pr_title_as_default": true,
              "visibility": "public",
              "watchers": 95,
              "watchers_count": 95,
              "web_commit_signoff_required": false
            },
            "sha": "13643d6165e76cf3442b9dbbf1eb365b9b523702",
            "user": {
              "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
              "events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
              "followers_url": "https://api.github.com/users/graphql-hive/followers",
              "following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
              "gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
              "gravatar_id": "",
              "html_url": "https://github.com/graphql-hive",
              "id": 182742256,
              "login": "graphql-hive",
              "node_id": "O_kgDOCuRs8A",
              "organizations_url": "https://api.github.com/users/graphql-hive/orgs",
              "received_events_url": "https://api.github.com/users/graphql-hive/received_events",
              "repos_url": "https://api.github.com/users/graphql-hive/repos",
              "site_admin": false,
              "starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
              "subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
              "type": "Organization",
              "url": "https://api.github.com/users/graphql-hive",
              "user_view_type": "public"
            }
          },
          "body": "Closes https://github.com/graphql-hive/router/issues/755 \r\nCloses https://github.com/graphql-hive/router/issues/765 \r\nCloses https://github.com/graphql-hive/router/issues/503 \r\n\r\nDocs PR: https://github.com/graphql-hive/docs/pull/147 \r\nDocs preview: https://a507d5b7-hive-platform-docs.theguild.workers.dev/graphql/hive/docs/router/observability/logging\r\n\r\n## Background \r\n\r\nExtracted only the crucial changes from https://github.com/graphql-hive/router/pull/775 and re-implements major parts of it. \r\n\r\n## Changes in this PR \r\n\r\n### Disable logging from internal crates \r\n\r\nA new config flag `log.log_internals` (default: `false`) has been added, that creates a `Targets` filter. It has a hardcoded list of log targets (mostly `ntex`) to remove and avoid printing. Most of `ntex` internal logging are noise, and we would like to avoid logging it, even when `debug` level is set. \r\n\r\nA user can enable these by setting `log.log_internals=true`, or by setting `LOG_INTERNALS=true` in the env. \r\n\r\n### Improved existing log lines \r\n\r\nThis PR also iterated all of the existing log lines (specifically the debug/info/warn/error levels) and adjusted the following:\r\n\r\n* User-based errors (like validation/parsing/invalid requests) are logged as warning, as they do not imply a router error. \r\n* Router-based/internal-errors (like failure to load schema or apply an internal process in the pipeline) are printed as errors level.\r\n* All log lines have `target` configured explicitly, so log lines are now much more clear and easy to read or filter.\r\n* Everything related to the router workflow/pipeline is printed as `debug`. No log lines are printed on the hotpath, expect for the summary (see below).\r\n* No nested `fields` or nested structued are printed, to allow log ingestors to process logs easily. \r\n* Added new log lines in decision areas of the Router, all under `DEBUG` level. \r\n\r\n### Structured Logging \r\n\r\nI've iterated all existing log lines and modified their attributes to be printed as-is, instead of printing it using a raw string. This allow JSON logging to be printed nicely and inspected by tools like DataDog or Grafana. \r\n\r\nThe `message` of each log line is only there to indicate and identify the even, and no log message contains information about the event. All data and fields are tracked as standalone fields, and they are not nested. \r\n\r\n### Performance impact \r\n\r\n`tracing` crate internal processes can be heavy. To avoid a major perf regression, while still allowing usersto get meaningful logs that are all-or-nothing, we've implement several mechanism and applied decisions to find the right balance:\r\n\r\n- We do not use `tracing`'s internal request-id correlation mechanism that is based on `span`s - this has a major impact since it records too many data items. Instead, we have a task-local implementation that tracks exactly what we need. \r\n- Custom logs formatters are in charge of correlation the log line with the request. \r\n- JSON log formatter is implemented from scratch, without performing any serialization (no serde / sonic_rs or any other itermediate representation). \r\n- The default log level is `INFO` and it prints only the request summary (see below), everything else is `DEBUG`. \r\n- All log lines that are lower than `DEBUG` in our code ( = `TRACE`) are dropped at compile time.\r\n\r\n### Custom log formatters \r\n\r\nFor `json` logging, we've implemented a custom formatter that does not construct any object, and avoid any JSON object allocations, or serialization. This means, that we construct the JSON output log lines, with a simple `buffer` that's also shared to avoid re-allocation for every log line. \r\n\r\nFor `text` logging, we use the `compact` format, but avoid re-allocation of new objects when possible.\r\n\r\nThe new, custom, log formatters are also in charge of injecting the request identifiers into every log line. \r\n\r\n### Access Logs / Request Summary\r\n\r\nWhile running the request, we attached a `RequestSummary` object that has a set of pre-defined attributes that are relevant for a request summary: \r\n\r\n```rs\r\npub struct RequestSummary {\r\n    pub client_name: OnceLock<String>,\r\n    pub client_version: OnceLock<String>,\r\n    pub operation_name: OnceLock<String>,\r\n    pub operation_type: OnceLock<&'static str>,\r\n    pub operation_hash: OnceLock<String>,\r\n    pub persisted_document_id: OnceLock<String>,\r\n    pub subgraph_requests: AtomicU32,\r\n    pub involved_subgraphs: Mutex<HashSet<String>>,\r\n    pub error_count: AtomicU32,\r\n    pub partial_response: AtomicBool,\r\n    pub response_code: OnceLock<&'static str>,\r\n    pub response_mode: OnceLock<&'static str>,\r\n    pub status_code: AtomicU16,\r\n    pub payload_bytes: AtomicI64,\r\n    pub duration_ms: AtomicU64,\r\n}\r\n```\r\n\r\nDuring execution, a task-local struct is attached to the request execution, and different part of the codebase can `record` information and hints about the execution. I tried to avoid any allocations where possible, but we can't avoid them all due to the need to use `'static` lifetime for the task-local variable. \r\n\r\nOnce a request completes, a single log line is printed on the `INFO` level, summarizes the request overall: \r\n\r\n> `2026-07-22T06:03:46.293394Z  INFO router::request: operation_name=“IntrospectionQuery” operation_hash=“1a9246e236afb66a7cccaf18c07c38f2\" subgraph_requests=0 involved_subgraphs=“” error_count=0 partial_response=false response_mode=“dual” status_code=200 payload_bytes=17302 duration_ms=3 request_id=629431863395501115` \r\n\r\n### Logs Correlation\r\n\r\nIn order to implement full request correlation, every incoming request is being inspected for both request-id and traceparent information. Both can be configured, or fully disabled from the config. \r\n\r\n```yaml\r\nlog:\r\n  correlation:\r\n    id_header: x-request-id\r\n    trace_propagation: true\r\n```\r\n\r\n<img width=\"1587\" height=\"180\" alt=\"image\" src=\"https://github.com/user-attachments/assets/0c0f5d28-f947-46ae-8b62-70990eec5c70\" />\r\n\r\nIn order to do that, we create a tokio task-specific variable that holds the request identifiers extracted from the request. Then the task-local data is passed to the request processing `Future`. \r\n\r\nIf a request doesn't have a `X-Request-ID` header, then Router will generate one for it, so logs lines are always correlated.  \r\n\r\n### Subscriptions support \r\n\r\nSame as HTTP, subscriptions also extract correlations and attached them, either based on the initial message headers, or based on the per-operation headers. \r\n\r\nWe do not print a log line for the initial HTTP part of Subscriptions, and we consider every operation execution on the subscriptions channel as a separate execution when it comes to requst-id correlation. \r\n\r\nRequest correlation is based on the headers that can be passed over the init message, or subscribe message. \r\n\r\nThe request-id and request-summary are being passed to the execution thread (as `Arc`) of subscriptions, so they can also correlate log lines and report summary details without effort.\r\n\r\nFor stream-based HTTP requests, I've implemented mechanism to \"bind\"/attach the summary and request-identifier to the response, so when `ntex` finally drops the response, it will `Drop` the summary object that will print the correct summary information. \r\nAlso, `duration_ms` for stream-based reports the final time of the request, since it was staretd. For `payload_bytes` it will be an accumulation of all bytes sent in all events. \r\n\r\n### Improved log filter\r\n\r\nThe existing `log.log_filter` (or `LOG_FILTER` env var) can now mute noise from the router itself, by doing something like `LOG_FILTER=router::supergraph=off`. This allow more granular control over specific targets and parts of the Router logs. \r\n\r\n### Non-blocking stdout logging \r\n\r\nInstead of using the default `stdout`, we are now using `tracing-appender`'s solution for non-blocking writing https://docs.rs/tracing-appender/latest/tracing_appender/#non-blocking-writer.\r\n\r\nAlso, the output is buffered so it won't print every character to the `stdout` immediately, to prevent over-flushing of data to the stdout. \r\n\r\n### Testing \r\n\r\nAdded some e2e to cover the important log lines, log attributes, req-id correlations, and also to test and cover the impact on OTEL (due to the \"fake\" span we create for the logging). \r\n\r\n## Breaking Changes \r\n\r\n* Log level `trace` no longer available \r\n* Log formats `pretty`, `tree` and `pretty-compact` no longer available, only `text` and `json` are available now.\r\n\r\n## TODO \r\n\r\n- [x] apply core changes from previous PR\r\n- [x] changes to code to make it more logging-friendly\r\n- [x] http request logging\r\n- [x] subgraph calls logging\r\n- [x] graphql layer logging\r\n- [x] env vars control \r\n- [x] bring back env-based log filter\r\n- [x] `trace` level in development only\r\n- [x] e2e testing\r\n- [x] subscriptions \r\n- [x] figure out perf regression\r\n- [x] subgraph call target \r\n- [x] subgraph http logging \r\n- [x] schema id in the log line \r\n- [x] subscriptions support (correlation over `spawn`)\r\n- [x] stream support (`duration_ms` + `payload_bytes`) \r\n- [x] sonyflake?\r\n- [x] changeset\r\n- [x] docs ",
          "changed_files": 80,
          "closed_at": null,
          "comments": 4,
          "comments_url": "https://api.github.com/repos/graphql-hive/router/issues/1283/comments",
          "commits": 27,
          "commits_url": "https://api.github.com/repos/graphql-hive/router/pulls/1283/commits",
          "created_at": "2026-07-15T18:25:59Z",
          "deletions": 820,
          "diff_url": "https://github.com/graphql-hive/router/pull/1283.diff",
          "draft": false,
          "head": {
            "label": "graphql-hive:minilog",
            "ref": "minilog",
            "repo": {
              "allow_auto_merge": false,
              "allow_forking": true,
              "allow_merge_commit": false,
              "allow_rebase_merge": false,
              "allow_squash_merge": true,
              "allow_update_branch": true,
              "archive_url": "https://api.github.com/repos/graphql-hive/router/{archive_format}{/ref}",
              "archived": false,
              "assignees_url": "https://api.github.com/repos/graphql-hive/router/assignees{/user}",
              "blobs_url": "https://api.github.com/repos/graphql-hive/router/git/blobs{/sha}",
              "branches_url": "https://api.github.com/repos/graphql-hive/router/branches{/branch}",
              "clone_url": "https://github.com/graphql-hive/router.git",
              "collaborators_url": "https://api.github.com/repos/graphql-hive/router/collaborators{/collaborator}",
              "comments_url": "https://api.github.com/repos/graphql-hive/router/comments{/number}",
              "commits_url": "https://api.github.com/repos/graphql-hive/router/commits{/sha}",
              "compare_url": "https://api.github.com/repos/graphql-hive/router/compare/{base}...{head}",
              "contents_url": "https://api.github.com/repos/graphql-hive/router/contents/{+path}",
              "contributors_url": "https://api.github.com/repos/graphql-hive/router/contributors",
              "created_at": "2024-11-20T16:16:12Z",
              "default_branch": "main",
              "delete_branch_on_merge": true,
              "deployments_url": "https://api.github.com/repos/graphql-hive/router/deployments",
              "description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
              "disabled": false,
              "downloads_url": "https://api.github.com/repos/graphql-hive/router/downloads",
              "events_url": "https://api.github.com/repos/graphql-hive/router/events",
              "fork": false,
              "forks": 16,
              "forks_count": 16,
              "forks_url": "https://api.github.com/repos/graphql-hive/router/forks",
              "full_name": "graphql-hive/router",
              "git_commits_url": "https://api.github.com/repos/graphql-hive/router/git/commits{/sha}",
              "git_refs_url": "https://api.github.com/repos/graphql-hive/router/git/refs{/sha}",
              "git_tags_url": "https://api.github.com/repos/graphql-hive/router/git/tags{/sha}",
              "git_url": "git://github.com/graphql-hive/router.git",
              "has_discussions": false,
              "has_downloads": false,
              "has_issues": true,
              "has_pages": false,
              "has_projects": false,
              "has_pull_requests": true,
              "has_wiki": false,
              "homepage": "https://the-guild.dev/graphql/hive/docs/router",
              "hooks_url": "https://api.github.com/repos/graphql-hive/router/hooks",
              "html_url": "https://github.com/graphql-hive/router",
              "id": 891604244,
              "is_template": false,
              "issue_comment_url": "https://api.github.com/repos/graphql-hive/router/issues/comments{/number}",
              "issue_events_url": "https://api.github.com/repos/graphql-hive/router/issues/events{/number}",
              "issues_url": "https://api.github.com/repos/graphql-hive/router/issues{/number}",
              "keys_url": "https://api.github.com/repos/graphql-hive/router/keys{/key_id}",
              "labels_url": "https://api.github.com/repos/graphql-hive/router/labels{/name}",
              "language": "Rust",
              "languages_url": "https://api.github.com/repos/graphql-hive/router/languages",
              "license": {
                "key": "mit",
                "name": "MIT License",
                "node_id": "MDc6TGljZW5zZTEz",
                "spdx_id": "MIT",
                "url": "https://api.github.com/licenses/mit"
              },
              "merge_commit_message": "PR_TITLE",
              "merge_commit_title": "MERGE_MESSAGE",
              "merges_url": "https://api.github.com/repos/graphql-hive/router/merges",
              "milestones_url": "https://api.github.com/repos/graphql-hive/router/milestones{/number}",
              "mirror_url": null,
              "name": "router",
              "node_id": "R_kgDONSTNFA",
              "notifications_url": "https://api.github.com/repos/graphql-hive/router/notifications{?since,all,participating}",
              "open_issues": 63,
              "open_issues_count": 63,
              "owner": {
                "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
                "events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
                "followers_url": "https://api.github.com/users/graphql-hive/followers",
                "following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
                "gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
                "gravatar_id": "",
                "html_url": "https://github.com/graphql-hive",
                "id": 182742256,
                "login": "graphql-hive",
                "node_id": "O_kgDOCuRs8A",
                "organizations_url": "https://api.github.com/users/graphql-hive/orgs",
                "received_events_url": "https://api.github.com/users/graphql-hive/received_events",
                "repos_url": "https://api.github.com/users/graphql-hive/repos",
                "site_admin": false,
                "starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
                "subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
                "type": "Organization",
                "url": "https://api.github.com/users/graphql-hive",
                "user_view_type": "public"
              },
              "private": false,
              "pull_request_creation_policy": "all",
              "pulls_url": "https://api.github.com/repos/graphql-hive/router/pulls{/number}",
              "pushed_at": "2026-07-26T15:24:58Z",
              "releases_url": "https://api.github.com/repos/graphql-hive/router/releases{/id}",
              "size": 10515,
              "squash_merge_commit_message": "PR_BODY",
              "squash_merge_commit_title": "PR_TITLE",
              "ssh_url": "git@github.com:graphql-hive/router.git",
              "stargazers_count": 95,
              "stargazers_url": "https://api.github.com/repos/graphql-hive/router/stargazers",
              "statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/{sha}",
              "subscribers_url": "https://api.github.com/repos/graphql-hive/router/subscribers",
              "subscription_url": "https://api.github.com/repos/graphql-hive/router/subscription",
              "svn_url": "https://github.com/graphql-hive/router",
              "tags_url": "https://api.github.com/repos/graphql-hive/router/tags",
              "teams_url": "https://api.github.com/repos/graphql-hive/router/teams",
              "topics": [
                "apollo-federation",
                "federation",
                "federation-gateway",
                "graphql",
                "graphql-federation",
                "router"
              ],
              "trees_url": "https://api.github.com/repos/graphql-hive/router/git/trees{/sha}",
              "updated_at": "2026-07-26T09:14:02Z",
              "url": "https://api.github.com/repos/graphql-hive/router",
              "use_squash_pr_title_as_default": true,
              "visibility": "public",
              "watchers": 95,
              "watchers_count": 95,
              "web_commit_signoff_required": false
            },
            "sha": "bf21c72004395639f5d1b19a60b1fc2d419d27f2",
            "user": {
              "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
              "events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
              "followers_url": "https://api.github.com/users/graphql-hive/followers",
              "following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
              "gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
              "gravatar_id": "",
              "html_url": "https://github.com/graphql-hive",
              "id": 182742256,
              "login": "graphql-hive",
              "node_id": "O_kgDOCuRs8A",
              "organizations_url": "https://api.github.com/users/graphql-hive/orgs",
              "received_events_url": "https://api.github.com/users/graphql-hive/received_events",
              "repos_url": "https://api.github.com/users/graphql-hive/repos",
              "site_admin": false,
              "starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
              "subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
              "type": "Organization",
              "url": "https://api.github.com/users/graphql-hive",
              "user_view_type": "public"
            }
          },
          "html_url": "https://github.com/graphql-hive/router/pull/1283",
          "id": 4062814180,
          "issue_url": "https://api.github.com/repos/graphql-hive/router/issues/1283",
          "labels": [],
          "locked": false,
          "maintainer_can_modify": false,
          "merge_commit_sha": "57391e94824b20a53535babe7cbfe7aa8e8d5d36",
          "mergeable": null,
          "mergeable_state": "unknown",
          "merged": false,
          "merged_at": null,
          "merged_by": null,
          "milestone": null,
          "node_id": "PR_kwDONSTNFM7yKZ_k",
          "number": 1283,
          "patch_url": "https://github.com/graphql-hive/router/pull/1283.patch",
          "rebaseable": null,
          "requested_reviewers": [
            {
              "avatar_url": "https://avatars.githubusercontent.com/u/8167190?v=4",
              "events_url": "https://api.github.com/users/kamilkisiela/events{/privacy}",
              "followers_url": "https://api.github.com/users/kamilkisiela/followers",
              "following_url": "https://api.github.com/users/kamilkisiela/following{/other_user}",
              "gists_url": "https://api.github.com/users/kamilkisiela/gists{/gist_id}",
              "gravatar_id": "",
              "html_url": "https://github.com/kamilkisiela",
              "id": 8167190,
              "login": "kamilkisiela",
              "node_id": "MDQ6VXNlcjgxNjcxOTA=",
              "organizations_url": "https://api.github.com/users/kamilkisiela/orgs",
              "received_events_url": "https://api.github.com/users/kamilkisiela/received_events",
              "repos_url": "https://api.github.com/users/kamilkisiela/repos",
              "site_admin": false,
              "starred_url": "https://api.github.com/users/kamilkisiela/starred{/owner}{/repo}",
              "subscriptions_url": "https://api.github.com/users/kamilkisiela/subscriptions",
              "type": "User",
              "url": "https://api.github.com/users/kamilkisiela",
              "user_view_type": "public"
            },
            {
              "avatar_url": "https://avatars.githubusercontent.com/in/946600?v=4",
              "events_url": "https://api.github.com/users/Copilot/events{/privacy}",
              "followers_url": "https://api.github.com/users/Copilot/followers",
              "following_url": "https://api.github.com/users/Copilot/following{/other_user}",
              "gists_url": "https://api.github.com/users/Copilot/gists{/gist_id}",
              "gravatar_id": "",
              "html_url": "https://github.com/apps/copilot-pull-request-reviewer",
              "id": 175728472,
              "login": "Copilot",
              "node_id": "BOT_kgDOCnlnWA",
              "organizations_url": "https://api.github.com/users/Copilot/orgs",
              "received_events_url": "https://api.github.com/users/Copilot/received_events",
              "repos_url": "https://api.github.com/users/Copilot/repos",
              "site_admin": false,
              "starred_url": "https://api.github.com/users/Copilot/starred{/owner}{/repo}",
              "subscriptions_url": "https://api.github.com/users/Copilot/subscriptions",
              "type": "Bot",
              "url": "https://api.github.com/users/Copilot",
              "user_view_type": "public"
            }
          ],
          "requested_teams": [],
          "review_comment_url": "https://api.github.com/repos/graphql-hive/router/pulls/comments{/number}",
          "review_comments": 65,
          "review_comments_url": "https://api.github.com/repos/graphql-hive/router/pulls/1283/comments",
          "state": "open",
          "statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/bf21c72004395639f5d1b19a60b1fc2d419d27f2",
          "title": "feat(router): logger improvements, access logs ",
          "updated_at": "2026-07-26T15:25:00Z",
          "url": "https://api.github.com/repos/graphql-hive/router/pulls/1283",
          "user": {
            "avatar_url": "https://avatars.githubusercontent.com/u/3680083?v=4",
            "events_url": "https://api.github.com/users/dotansimha/events{/privacy}",
            "followers_url": "https://api.github.com/users/dotansimha/followers",
            "following_url": "https://api.github.com/users/dotansimha/following{/other_user}",
            "gists_url": "https://api.github.com/users/dotansimha/gists{/gist_id}",
            "gravatar_id": "",
            "html_url": "https://github.com/dotansimha",
            "id": 3680083,
            "login": "dotansimha",
            "node_id": "MDQ6VXNlcjM2ODAwODM=",
            "organizations_url": "https://api.github.com/users/dotansimha/orgs",
            "received_events_url": "https://api.github.com/users/dotansimha/received_events",
            "repos_url": "https://api.github.com/users/dotansimha/repos",
            "site_admin": false,
            "starred_url": "https://api.github.com/users/dotansimha/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/dotansimha/subscriptions",
            "type": "User",
            "url": "https://api.github.com/users/dotansimha",
            "user_view_type": "public"
          }
        },
        "repository": {
          "allow_forking": true,
          "archive_url": "https://api.github.com/repos/graphql-hive/router/{archive_format}{/ref}",
          "archived": false,
          "assignees_url": "https://api.github.com/repos/graphql-hive/router/assignees{/user}",
          "blobs_url": "https://api.github.com/repos/graphql-hive/router/git/blobs{/sha}",
          "branches_url": "https://api.github.com/repos/graphql-hive/router/branches{/branch}",
          "clone_url": "https://github.com/graphql-hive/router.git",
          "collaborators_url": "https://api.github.com/repos/graphql-hive/router/collaborators{/collaborator}",
          "comments_url": "https://api.github.com/repos/graphql-hive/router/comments{/number}",
          "commits_url": "https://api.github.com/repos/graphql-hive/router/commits{/sha}",
          "compare_url": "https://api.github.com/repos/graphql-hive/router/compare/{base}...{head}",
          "contents_url": "https://api.github.com/repos/graphql-hive/router/contents/{+path}",
          "contributors_url": "https://api.github.com/repos/graphql-hive/router/contributors",
          "created_at": "2024-11-20T16:16:12Z",
          "custom_properties": {
            "vanta_production_branch_name": "main"
          },
          "default_branch": "main",
          "deployments_url": "https://api.github.com/repos/graphql-hive/router/deployments",
          "description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
          "disabled": false,
          "downloads_url": "https://api.github.com/repos/graphql-hive/router/downloads",
          "events_url": "https://api.github.com/repos/graphql-hive/router/events",
          "fork": false,
          "forks": 16,
          "forks_count": 16,
          "forks_url": "https://api.github.com/repos/graphql-hive/router/forks",
          "full_name": "graphql-hive/router",
          "git_commits_url": "https://api.github.com/repos/graphql-hive/router/git/commits{/sha}",
          "git_refs_url": "https://api.github.com/repos/graphql-hive/router/git/refs{/sha}",
          "git_tags_url": "https://api.github.com/repos/graphql-hive/router/git/tags{/sha}",
          "git_url": "git://github.com/graphql-hive/router.git",
          "has_discussions": false,
          "has_downloads": false,
          "has_issues": true,
          "has_pages": false,
          "has_projects": false,
          "has_pull_requests": true,
          "has_wiki": false,
          "homepage": "https://the-guild.dev/graphql/hive/docs/router",
          "hooks_url": "https://api.github.com/repos/graphql-hive/router/hooks",
          "html_url": "https://github.com/graphql-hive/router",
          "id": 891604244,
          "is_template": false,
          "issue_comment_url": "https://api.github.com/repos/graphql-hive/router/issues/comments{/number}",
          "issue_events_url": "https://api.github.com/repos/graphql-hive/router/issues/events{/number}",
          "issues_url": "https://api.github.com/repos/graphql-hive/router/issues{/number}",
          "keys_url": "https://api.github.com/repos/graphql-hive/router/keys{/key_id}",
          "labels_url": "https://api.github.com/repos/graphql-hive/router/labels{/name}",
          "language": "Rust",
          "languages_url": "https://api.github.com/repos/graphql-hive/router/languages",
          "license": {
            "key": "mit",
            "name": "MIT License",
            "node_id": "MDc6TGljZW5zZTEz",
            "spdx_id": "MIT",
            "url": "https://api.github.com/licenses/mit"
          },
          "merges_url": "https://api.github.com/repos/graphql-hive/router/merges",
          "milestones_url": "https://api.github.com/repos/graphql-hive/router/milestones{/number}",
          "mirror_url": null,
          "name": "router",
          "node_id": "R_kgDONSTNFA",
          "notifications_url": "https://api.github.com/repos/graphql-hive/router/notifications{?since,all,participating}",
          "open_issues": 63,
          "open_issues_count": 63,
          "owner": {
            "avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
            "events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
            "followers_url": "https://api.github.com/users/graphql-hive/followers",
            "following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
            "gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
            "gravatar_id": "",
            "html_url": "https://github.com/graphql-hive",
            "id": 182742256,
            "login": "graphql-hive",
            "node_id": "O_kgDOCuRs8A",
            "organizations_url": "https://api.github.com/users/graphql-hive/orgs",
            "received_events_url": "https://api.github.com/users/graphql-hive/received_events",
            "repos_url": "https://api.github.com/users/graphql-hive/repos",
            "site_admin": false,
            "starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
            "type": "Organization",
            "url": "https://api.github.com/users/graphql-hive",
            "user_view_type": "public"
          },
          "private": false,
          "pull_request_creation_policy": "all",
          "pulls_url": "https://api.github.com/repos/graphql-hive/router/pulls{/number}",
          "pushed_at": "2026-07-26T15:24:58Z",
          "releases_url": "https://api.github.com/repos/graphql-hive/router/releases{/id}",
          "size": 10515,
          "ssh_url": "git@github.com:graphql-hive/router.git",
          "stargazers_count": 95,
          "stargazers_url": "https://api.github.com/repos/graphql-hive/router/stargazers",
          "statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/{sha}",
          "subscribers_url": "https://api.github.com/repos/graphql-hive/router/subscribers",
          "subscription_url": "https://api.github.com/repos/graphql-hive/router/subscription",
          "svn_url": "https://github.com/graphql-hive/router",
          "tags_url": "https://api.github.com/repos/graphql-hive/router/tags",
          "teams_url": "https://api.github.com/repos/graphql-hive/router/teams",
          "topics": [
            "apollo-federation",
            "federation",
            "federation-gateway",
            "graphql",
            "graphql-federation",
            "router"
          ],
          "trees_url": "https://api.github.com/repos/graphql-hive/router/git/trees{/sha}",
          "updated_at": "2026-07-26T09:14:02Z",
          "url": "https://api.github.com/repos/graphql-hive/router",
          "visibility": "public",
          "watchers": 95,
          "watchers_count": 95,
          "web_commit_signoff_required": false
        },
        "sender": {
          "avatar_url": "https://avatars.githubusercontent.com/u/3680083?v=4",
          "events_url": "https://api.github.com/users/dotansimha/events{/privacy}",
          "followers_url": "https://api.github.com/users/dotansimha/followers",
          "following_url": "https://api.github.com/users/dotansimha/following{/other_user}",
          "gists_url": "https://api.github.com/users/dotansimha/gists{/gist_id}",
          "gravatar_id": "",
          "html_url": "https://github.com/dotansimha",
          "id": 3680083,
          "login": "dotansimha",
          "node_id": "MDQ6VXNlcjM2ODAwODM=",
          "organizations_url": "https://api.github.com/users/dotansimha/orgs",
          "received_events_url": "https://api.github.com/users/dotansimha/received_events",
          "repos_url": "https://api.github.com/users/dotansimha/repos",
          "site_admin": false,
          "starred_url": "https://api.github.com/users/dotansimha/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/dotansimha/subscriptions",
          "type": "User",
          "url": "https://api.github.com/users/dotansimha",
          "user_view_type": "public"
        }
      },
      "github_job": "docker",
      "github_ref": "refs/pull/1283/merge",
      "github_ref_name": "1283/merge",
      "github_ref_protected": "false",
      "github_ref_type": "branch",
      "github_repository": "graphql-hive/router",
      "github_repository_id": "891604244",
      "github_repository_owner": "graphql-hive",
      "github_repository_owner_id": "182742256",
      "github_run_attempt": "1",
      "github_run_id": "30208149531",
      "github_run_number": "4644",
      "github_runner_arch": "X64",
      "github_runner_environment": "github-hosted",
      "github_runner_image_os": "ubuntu24",
      "github_runner_image_version": "20260720.247.2",
      "github_runner_name": "GitHub Actions 1000933918",
      "github_runner_os": "Linux",
      "github_runner_tracking_id": "github_cde20512-a663-4ffd-b6e2-d12f494b3652",
      "github_server_url": "https://github.com",
      "github_triggering_actor": "dotansimha",
      "github_workflow": "build-router",
      "github_workflow_ref": "graphql-hive/router/.github/workflows/build-router.yaml@refs/pull/1283/merge",
      "github_workflow_sha": "ebd2267e07f094d8ffff141a2466714f698bb062",
      "platform": "linux/amd64"
    }
  }
},
"buildx.build.ref": "builder-c1264e41-3221-4661-b4f3-fac8e7706fa1/builder-c1264e41-3221-4661-b4f3-fac8e7706fa10/4ytthw2bbocbib724eltjmw8j",
"containerimage.descriptor": {
  "mediaType": "application/vnd.oci.image.index.v1+json",
  "digest": "sha256:4f7222d3dbd69e81ac289ed7f18ac4315fd46d7e4325bb47293a41a908c9466c",
  "size": 1609
},
"containerimage.digest": "sha256:4f7222d3dbd69e81ac289ed7f18ac4315fd46d7e4325bb47293a41a908c9466c",
"image.name": "ghcr.io/graphql-hive/router:pr-1283,ghcr.io/graphql-hive/router:sha-ebd2267"
}

@dotansimha
dotansimha force-pushed the minilog branch 13 times, most recently from d10d926 to 56cd095 Compare July 20, 2026 09:20
@dotansimha dotansimha changed the title feat(router): logger improvements feat(router): logger improvements, access logs Jul 22, 2026
Copilot AI review requested due to automatic review settings July 22, 2026 09:21

Copilot AI 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.

Pull request overview

This PR reworks the router’s logging subsystem to provide structured, correlatable logs (request-id + optional trace-id), reduce noisy internal-crate output by default, and add request-summary (“access log”) style emission, along with new e2e coverage around stdout log contents.

Changes:

  • Added logging correlation configuration (log.correlation) and log.log_internals filtering, including env var overrides.
  • Implemented custom JSON/text tracing_subscriber formatters that inject request identifiers into every log line without serde-based JSON serialization.
  • Expanded/normalized structured log targets across the router + SDK crates and added e2e tests for log shape and correlation.

Reviewed changes

Copilot reviewed 73 out of 76 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
package-lock.json Marks some dependencies as peer to reflect package metadata changes.
lib/router-config/src/log.rs Adds correlation + log_internals config; restricts formats/levels; adds LevelFilter conversion.
lib/router-config/src/env_overrides.rs Adds LOG_INTERNALS override; restructures override logs with explicit targets/fields.
lib/internal/src/telemetry/traces/trace_batch_span_processor.rs Adds explicit telemetry log target and improves structured error fields.
lib/internal/src/telemetry/traces/hive_console_exporter.rs Normalizes telemetry exporter logs to use targets::TELEMETRY + structured fields.
lib/internal/src/telemetry/traces/compatibility.rs Normalizes http compatibility exporter shutdown logs to telemetry target.
lib/internal/src/telemetry/mod.rs Introduces telemetry::logging module and request-id extractor in TelemetryContext.
lib/internal/src/telemetry/metrics/setup.rs Adds explicit telemetry target for metrics setup warnings.
lib/internal/src/telemetry/logging/utils.rs Adds internal-crate target filtering + OTEL span filtering helpers.
lib/internal/src/telemetry/logging/targets.rs Centralizes log target strings for consistent filtering/querying.
lib/internal/src/telemetry/logging/summary.rs Implements RequestSummary task-local request summary/access-log emission.
lib/internal/src/telemetry/logging/request_id.rs Adds request-id + trace-id extraction and task-local scoping utilities.
lib/internal/src/telemetry/logging/mod.rs Exposes new logging submodules.
lib/internal/src/telemetry/logging/format_text.rs Custom text formatter that appends request identifiers to each line.
lib/internal/src/telemetry/logging/format_json.rs Custom JSON formatter writing JSON directly into a buffer (no serde object creation).
lib/internal/src/background_tasks/mod.rs Adds explicit targets and structured fields for background task logs.
lib/internal/Cargo.toml Adds sonyflake + chrono for request-id generation and timestamp formatting.
lib/hive-console-sdk/src/supergraph_fetcher/sync_fetcher.rs Adds an explicit target + structured error logging.
lib/hive-console-sdk/src/supergraph_fetcher/mod.rs Adds SUPERGRAPH_FETCHER_TARGET constant for consistent targeting.
lib/hive-console-sdk/src/persisted_documents.rs Converts persisted-doc logs to structured debug/warn with a fixed target.
lib/hive-console-sdk/src/agent/usage_agent.rs Removes stdout println!, adds structured logs + target constants.
lib/executor/src/projection/plan.rs Adds explicit target usage for projection debug/warn logs.
lib/executor/src/headers/cache_control.rs Adds explicit cache-control target and more structured fields.
lib/executor/src/executors/websocket.rs Adds executor naming + structured websocket client logs.
lib/executor/src/executors/websocket_common.rs Adds explicit websocket client target and structured error logs.
lib/executor/src/executors/websocket_client.rs Adds websocket-client target and structured logs (plus new subscription trace field).
lib/executor/src/executors/subscription_buffer.rs Adds subscriptions target and normalizes field names.
lib/executor/src/executors/map.rs Adds structured demand-control + execution logs and executor name usage.
lib/executor/src/executors/http.rs Adds executor naming and structured HTTP client logs; records subgraph info into summary.
lib/executor/src/executors/http_callback.rs Adds executor naming and structured callback logging with explicit target.
lib/executor/src/executors/graphql_transport_ws.rs Adds explicit websocket target for JSON serialization errors.
lib/executor/src/executors/common.rs Extends SubgraphExecutor trait with executor_name().
lib/executor/src/execution/plan.rs Normalizes execution error logs/targets and records partial response in summary.
lib/executor/src/coprocessor/runtime.rs Converts coprocessor logs to structured fields + explicit targets.
e2e/src/testkit/stdout.rs Adds stdout capture helpers to assert log output lines/JSON in e2e tests.
e2e/src/testkit/mod.rs Exposes the stdout capture testkit module.
e2e/src/telemetry/mod.rs Adds telemetry logging e2e module.
e2e/src/telemetry/logging.rs Adds e2e tests for log structure, correlation, and OTEL coexistence.
e2e/Cargo.toml Adds gag dependency for capturing stdout in tests.
docs/README.md Updates documented logging schema (format/level enums, correlation config, defaults).
Cargo.toml Updates insta features, enables tracing compile-time level caps, adds tracing-appender.
Cargo.lock Lockfile updates for new crates/features (gag, sonyflake, tracing-appender, etc.).
bin/router/src/telemetry.rs Replaces prior logging setup with non-blocking writer + custom JSON/text formatters and filters.
bin/router/src/supergraph/storage.rs Converts supergraph storage load errors to structured logs/targets.
bin/router/src/supergraph/mod.rs Adds explicit supergraph target and structured loader creation logging.
bin/router/src/supergraph/hive.rs Converts Hive supergraph loader logs to structured fields/targets.
bin/router/src/supergraph/file.rs Converts file supergraph loader logs to structured fields/targets.
bin/router/src/storage/s3_runtime.rs Converts s3 load warnings to error! with storage target.
bin/router/src/storage/mod.rs Adds storage target and structured runtime creation logs.
bin/router/src/shared_state.rs Adds subscriptions target to lag/drop logs.
bin/router/src/schema_state.rs Normalizes supergraph lifecycle logs to explicit targets + structured fields.
bin/router/src/plugins/registry.rs Normalizes plugin init logs with explicit plugin target + structured error fields.
bin/router/src/pipeline/websocket_server.rs Adds structured websocket server logs and hooks in correlation/summary into subscription execution flow.
bin/router/src/pipeline/validation/mod.rs Converts validation failure logging to warn+debug with structured fields/targets.
bin/router/src/pipeline/usage_reporting.rs Adds hive usage reporting target + structured error logging.
bin/router/src/pipeline/persisted_documents/resolve/storage.rs Adds persisted-documents target + structured logs for reload behavior.
bin/router/src/pipeline/persisted_documents/resolve/fs.rs Adds persisted-documents target + structured watcher/reload logs.
bin/router/src/pipeline/parser.rs Normalizes parse/minify failure logs with explicit parsing target and structured errors.
bin/router/src/pipeline/normalize.rs Converts normalization trace logs into structured debug output.
bin/router/src/pipeline/mod.rs Adds structured HTTP server + GraphQL execution logs and records request summary fields.
bin/router/src/pipeline/introspection_policy.rs Changes introspection rejection to warn with explicit target.
bin/router/src/pipeline/http_callback.rs Restructures callback errors (less message detail) and logs with subscriptions target.
bin/router/src/pipeline/header.rs Adds ResponseMode::as_str() and structured Accept-header parse warnings.
bin/router/src/pipeline/execution_request.rs Normalizes HTTP server warnings and persisted-doc missing-id logging target/level.
bin/router/src/pipeline/error.rs Records response code into request summary on pipeline errors.
bin/router/src/pipeline/demand_control/runtime.rs Adds demand-control target + structured logs for enforcement/measurement.
bin/router/src/pipeline/demand_control/formula.rs Adds demand-control target to warnings.
bin/router/src/pipeline/csrf_prevention.rs Adds HTTP server targeted warning on CSRF failure.
bin/router/src/pipeline/coerce_variables.rs Adds coerce-variables target and structured fields.
bin/router/src/pipeline/authorization/mod.rs Changes unauthorized reject logging to warn with authorization target.
bin/router/src/pipeline/active_subscriptions.rs Adds subscriptions target to subscription lifecycle traces.
bin/router/src/lib.rs Adds HTTP request start/end logs and wires correlation + request summary scoping into request handling.
bin/router/src/jwt/mod.rs Normalizes JWT logs to structured fields with JWT target.
bin/router/src/jwt/jwks_manager.rs Adds JWT target to logs and improves structured fields for JWKS polling/load failures.
bin/router/Cargo.toml Replaces tracing-tree with tracing-appender dependency for non-blocking output.
apollo-router-workspace/bin/router/src/persisted_documents.rs Lowers persisted-doc “found” log from info to debug.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/executor/src/executors/websocket_client.rs Outdated
Comment thread lib/internal/src/telemetry/traces/trace_batch_span_processor.rs
Comment thread bin/router/src/pipeline/coerce_variables.rs
Comment thread lib/internal/src/telemetry/logging/summary.rs
Comment thread e2e/src/telemetry/logging.rs
Comment thread bin/router/src/pipeline/websocket_server.rs
Comment thread bin/router/src/pipeline/websocket_server.rs
Comment thread lib/internal/src/telemetry/logging/request_id.rs
Copilot AI review requested due to automatic review settings July 22, 2026 10:15
@dotansimha
dotansimha force-pushed the minilog branch 2 times, most recently from c8a3cce to 2d31051 Compare July 22, 2026 10:15
@dotansimha
dotansimha requested review from Copilot and removed request for Copilot July 22, 2026 10:18
Copilot AI review requested due to automatic review settings July 26, 2026 10:47

Copilot AI 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.

Pull request overview

Copilot reviewed 77 out of 80 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (2)

lib/internal/src/telemetry/logging/format_text.rs:42

  • Text log output appends request_id/trace_id as raw values (request_id=...). Even though request_id is sanitized, it still allows characters like = / + that can break simple key=value parsers; quoting/escaping these values in text output makes the log line robust for downstream parsing.
    lib/internal/src/telemetry/logging/request_id.rs:49
  • RequestIdentifierExtractor::new panics if Sonyflake::new() fails (e.g., missing/unsupported network interfaces or other platform constraints). Since this runs during telemetry/logging setup, this can crash the router at startup in some containerized/sandboxed environments. Consider handling the failure gracefully (log + fall back to a different generator such as ULID/UUID, or keep generator: Option<Sonyflake> and use the existing timestamp fallback without panicking). Also, the current timestamp fallback uses seconds, which can collide under concurrent load; using higher resolution (millis/nanos) would reduce collision risk.

Copilot AI review requested due to automatic review settings July 26, 2026 10:50

Copilot AI 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.

Pull request overview

Copilot reviewed 77 out of 80 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (3)

lib/internal/src/telemetry/logging/format_text.rs:43

  • request_id / trace_id are appended as raw text without any quoting/escaping. Even with upstream sanitization, values like = or / can make the final line ambiguous for downstream key=value parsers, and it diverges from how tracing_subscriber formats other string fields. Prefer emitting them as quoted/escaped values (e.g. via {:?}) to make the text format robust.
    e2e/src/testkit/stdout.rs:20
  • BufferRedirect::stdout() redirects stdout process-wide. Since Rust tests run in parallel by default, concurrent use of StdoutLogCapture can interleave/corrupt captured output and make logging e2e tests flaky. Consider serializing stdout capture with a global lock held for the lifetime of StdoutLogCapture.
    lib/internal/src/telemetry/logging/request_id.rs:49
  • RequestIdentifierExtractor::new uses expect(...) on Sonyflake::new(). Sonyflake initialization can fail (e.g. missing/unsupported network interfaces in some container setups), which would crash the router during startup. Prefer avoiding a hard panic here (e.g. log a warning and fall back to timestamp-only IDs, or make initialization fallible and surface a configuration/runtime error).

Copilot AI 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.

Pull request overview

Copilot reviewed 77 out of 80 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (2)

lib/internal/src/telemetry/logging/request_id.rs:49

  • RequestIdentifierExtractor::new uses Sonyflake::new().expect(...), which will panic and crash the router at startup if sonyflake cannot initialize (e.g., restricted/ephemeral network interface environments). This turns a correlation/logging feature into a hard availability risk; consider handling initialization failure and falling back to the timestamp-based ID path (or another non-panicking generator).
    bin/router/src/lib.rs:736
  • The doc comment above init_rustls_crypto_provider says repeated calls should "log a warning", but the implementation logs at error level. This makes an expected/handled condition look like a failure in production logs and alerting.
pub fn init_rustls_crypto_provider() {
    if rustls::crypto::aws_lc_rs::default_provider()
        .install_default()
        .is_err()
    {
        error!(target: targets::TLS, "rustls crypto provider already installed, ignoring");
    }

Comment thread lib/executor/src/executors/websocket_common.rs
Comment thread lib/internal/src/telemetry/mod.rs

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

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.

Access logs Correlate log lines with request identifiers logger identifier for the schema version

3 participants