Skip to content

Conversation

@GeoffreyWang1117
Copy link

Summary

  • Add new CLI option --uvicorn-access-log-exclude-paths to selectively exclude specific paths from uvicorn access logs
  • This is useful for filtering out noisy endpoints like /health and /metrics that are frequently polled by monitoring systems
  • Implements a UvicornAccessLogFilter class that filters log records based on the request path

Usage Example

vllm serve model-name \
    --uvicorn-access-log-exclude-paths /metrics \
    --uvicorn-access-log-exclude-paths /health

Test plan

  • Unit tested the UvicornAccessLogFilter class with various path patterns
  • Verified /metrics and /health paths are correctly filtered
  • Verified other paths like /v1/chat/completions pass through correctly
  • Verified pre-commit checks pass

Fixes #29023

Signed-off-by: GeoffreyWang1117 173976389+GeoffreyWang1117@users.noreply.github.com

Add a new CLI option to selectively exclude specific paths from
uvicorn access logs. This is useful for filtering out noisy endpoints
like /health and /metrics that are frequently polled by monitoring
systems.

Usage example:
  vllm serve model --uvicorn-access-log-exclude-paths /metrics \
                   --uvicorn-access-log-exclude-paths /health

Fixes vllm-project#29023

Signed-off-by: GeoffreyWang1117 <173976389+GeoffreyWang1117@users.noreply.github.com>
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

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 a new CLI option --uvicorn-access-log-exclude-paths to filter uvicorn access logs, which is a useful feature for reducing log noise from health checks and metrics endpoints. The implementation adds a new UvicornAccessLogFilter class. My review focuses on the correctness of this filter's logic. I've identified a critical issue in the filter method that could lead to incorrect log filtering and have provided a suggestion to make it more robust and correct.

Comment on lines +39 to +55
def filter(self, record: logging.LogRecord) -> bool:
# Uvicorn access log format: '%(client_addr)s - "%(request_line)s" %(status_code)s' # noqa: E501
# The request line contains the method, path, and protocol.
# Example: '127.0.0.1:12345 - "GET /metrics HTTP/1.1" 200'
if hasattr(record, "scope"):
path = record.scope.get("path", "") # type: ignore[union-attr]
if path in self.exclude_paths:
return False
# Fallback: check the message for the path
# The path appears after the HTTP method (GET, POST, etc.)
# Pattern: 'METHOD /path ' or 'METHOD /path"'
message = record.getMessage()
for path in self.exclude_paths:
# Match patterns like: "GET /metrics " or "POST /health HTTP"
if f" {path} " in message or f' {path}"' in message:
return False
return True
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

The filter method has two issues that can lead to incorrect log filtering:

  1. Incorrect Fall-through Logic: When a log record has a scope attribute, the path is correctly extracted. However, if this path is not in exclude_paths, the code incorrectly falls through to the string-based fallback logic instead of immediately returning True. The scope attribute should be treated as the source of truth, and the fallback should only be engaged if scope is absent.

  2. Fragile Fallback for Query Parameters: The fallback logic, which parses the log message as a plain string, does not correctly handle URL query parameters. For instance, a request to /health?foo=bar will not be filtered even if /health is specified in exclude_paths, because the string matching for " /health " will fail.

I suggest refactoring the filter method to fix these issues. The proposed change ensures that if scope is present, a definitive filtering decision is made. If not, it uses a more robust fallback mechanism that correctly parses the path from the request line, even with query parameters.

    def filter(self, record: logging.LogRecord) -> bool:
        # Uvicorn access log format: '%(client_addr)s - "%(request_line)s" %(status_code)s'  # noqa: E501
        # The request line contains the method, path, and protocol.
        # Example: '127.0.0.1:12345 - "GET /metrics HTTP/1.1" 200'
        if hasattr(record, "scope"):
            path = record.scope.get("path", "")  # type: ignore[union-attr]
            # The `path` from scope is the source of truth.
            # If it's not in exclude_paths, we should log it.
            return path not in self.exclude_paths

        # Fallback: check the message for the path
        # The request line is typically quoted: "METHOD /path?query HTTP/1.1"
        # We'll look for the path within the quotes.
        message = record.getMessage()
        try:
            request_line = message.split('"')[1]
            path_with_query = request_line.split(" ", 2)[1]
            path = path_with_query.split("?", 1)[0]
            if path in self.exclude_paths:
                return False
        except IndexError:
            # If the message format is unexpected, we can't reliably filter.
            # It's safer to log than to incorrectly filter.
            pass
        return True

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Disable logging /metrics

1 participant