Skip to content

[Serve] Add client IP address to HTTP access logs#60967

Merged
abrarsheikh merged 12 commits into
masterfrom
add-client-ip-in-access-log
Mar 16, 2026
Merged

[Serve] Add client IP address to HTTP access logs#60967
abrarsheikh merged 12 commits into
masterfrom
add-client-ip-in-access-log

Conversation

@harshit-anyscale

@harshit-anyscale harshit-anyscale commented Feb 11, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add client IP:port to Ray Serve HTTP access logs
  • Thread client address from the proxy through the request context and metadata to the replica
  • Handle both proxy-routed and direct ingress HTTP paths

For services behind a load balancer, uvicorn's ProxyHeadersMiddleware (enabled by default) resolves X-Forwarded-For into scope["client"] automatically, so the logged IP reflects the original client when FORWARDED_ALLOW_IPS is configured.

How It Works

The client IP is available at the entry point (proxy or direct ingress replica) but needs to reach the replica's access log, which runs in a separate process. The data flows through existing infrastructure:

External Client (10.0.91.46:54321)
       |
   [ Proxy ]
       |  1. Reads scope["client"] via proxy_request.client
       |  2. format_client_address() formats the raw tuple into "host:port"
       |  3. Logs it in the proxy access log
       |  4. Passes it into _RequestContext._client
       |
   [ DeploymentHandle ]
       |  5. default_impl.py copies _RequestContext._client → RequestMetadata._client
       |
   [ Replica ]
       |  6. Reads request_metadata._client and logs it in the replica access log

For direct ingress HTTP (replica serves HTTP directly, no proxy), the replica reads scope["client"] itself and formats it with the same format_client_address().


Update: Feature flag gating

Per review feedback, the client IP logging is now gated behind a feature flag that is off by default:

RAY_SERVE_LOG_CLIENT_ADDRESS=1

The gate is centralized in access_log_msg() in logging_utils.py — when the flag is off, the client parameter is ignored and the log format is unchanged from before this PR. The client address data still flows through the request context, but is simply not rendered in logs unless the flag is enabled.

Tests: Added a parametrized integration test (test_http_access_log_client_address) that verifies both flag states — client IP present when on, absent when off.

Signed-off-by: harshit <harshit@anyscale.com>
@harshit-anyscale harshit-anyscale self-assigned this Feb 11, 2026
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@harshit-anyscale harshit-anyscale changed the title add client ip in the access log Feb 11, 2026
@harshit-anyscale harshit-anyscale added the go add ONLY when ready to merge, run all tests label Feb 11, 2026
@harshit-anyscale harshit-anyscale marked this pull request as ready for review February 11, 2026 08:42
@harshit-anyscale harshit-anyscale requested a review from a team as a code owner February 11, 2026 08:42
Comment thread python/ray/serve/_private/logging_utils.py Outdated

@abrarsheikh abrarsheikh 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.

let's gate this feature behind a feature flag, which is off by default.

…ture flag

The client IP logging feature is now off by default for privacy.
Set RAY_SERVE_LOG_CLIENT_ADDRESS=1 to enable it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: harshit <harshit@anyscale.com>
@harshit-anyscale

Copy link
Copy Markdown
Contributor Author

let's gate this feature behind a feature flag, which is off by default.

done.

…rrors

The test uses serve_and_ray_shutdown which kills the shared Ray instance.
Placing it between serve_instance tests caused subsequent teardowns to fail
with "Client has already been shut down." Move it to the serve_and_ray_shutdown
test section at the bottom of the file.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: harshit <harshit@anyscale.com>
Comment thread python/ray/serve/_private/logging_utils.py Outdated
Comment thread python/ray/serve/tests/test_logging.py
harshit-anyscale and others added 2 commits February 18, 2026 07:00
Address review feedback: fix ambiguous IPv6 log output (e.g. ::1:54321
-> [::1]:54321), add client address extraction for gRPC requests via
context.peer(), propagate _client through request context in replicas
for handle-to-handle calls, and add gRPC access log integration test.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: harshit <harshit@anyscale.com>
harshit-anyscale and others added 2 commits February 18, 2026 17:54
Move gRPC-specific imports back to inline inside the test function and
skip test_grpc_access_log_client_address when RAY_SERVE_ENABLE_HA_PROXY
is enabled, since the gRPC test is not compatible with HAProxy CI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: harshit <harshit@anyscale.com>
Signed-off-by: harshit <harshit@anyscale.com>
Comment thread python/ray/serve/_private/replica.py Outdated
Signed-off-by: harshit <harshit@anyscale.com>
@ray-gardener ray-gardener Bot added serve Ray Serve Related Issue observability Issues related to the Ray Dashboard, Logging, Metrics, Tracing, and/or Profiling labels Feb 27, 2026
Signed-off-by: harshit <harshit@anyscale.com>
Comment thread python/ray/serve/_private/proxy_request_response.py

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Comment thread python/ray/serve/_private/proxy_request_response.py
Signed-off-by: harshit <harshit@anyscale.com>
@abrarsheikh abrarsheikh merged commit 68a622a into master Mar 16, 2026
6 checks passed
@abrarsheikh abrarsheikh deleted the add-client-ip-in-access-log branch March 16, 2026 17:34
Lucas61000 pushed a commit to Lucas61000/ray that referenced this pull request May 15, 2026
## Summary
- Add client IP:port to Ray Serve HTTP access logs
- Thread client address from the proxy through the request context and
metadata to the replica
- Handle both proxy-routed and direct ingress HTTP paths

For services behind a load balancer, uvicorn's `ProxyHeadersMiddleware`
(enabled by default) resolves `X-Forwarded-For` into `scope["client"]`
automatically, so the logged IP reflects the original client when
`FORWARDED_ALLOW_IPS` is configured.

## How It Works

The client IP is available at the entry point (proxy or direct ingress
replica) but needs to reach the replica's access log, which runs in a
separate process. The data flows through existing infrastructure:

```
External Client (10.0.91.46:54321)
       |
   [ Proxy ]
       |  1. Reads scope["client"] via proxy_request.client
       |  2. format_client_address() formats the raw tuple into "host:port"
       |  3. Logs it in the proxy access log
       |  4. Passes it into _RequestContext._client
       |
   [ DeploymentHandle ]
       |  5. default_impl.py copies _RequestContext._client → RequestMetadata._client
       |
   [ Replica ]
       |  6. Reads request_metadata._client and logs it in the replica access log
```

For **direct ingress HTTP** (replica serves HTTP directly, no proxy),
the replica reads `scope["client"]` itself and formats it with the same
`format_client_address()`.

---

## Update: Feature flag gating

Per review feedback, the client IP logging is now gated behind a feature
flag that is **off by default**:

```
RAY_SERVE_LOG_CLIENT_ADDRESS=1
```

The gate is centralized in `access_log_msg()` in `logging_utils.py` —
when the flag is off, the `client` parameter is ignored and the log
format is unchanged from before this PR. The client address data still
flows through the request context, but is simply not rendered in logs
unless the flag is enabled.

**Tests:** Added a parametrized integration test
(`test_http_access_log_client_address`) that verifies both flag states —
client IP present when on, absent when off.

---------

Signed-off-by: harshit <harshit@anyscale.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

go add ONLY when ready to merge, run all tests observability Issues related to the Ray Dashboard, Logging, Metrics, Tracing, and/or Profiling serve Ray Serve Related Issue

2 participants