def log_request(handler):
    """log a bit more information about each request than tornado's default

    - move static file get success to debug-level (reduces noise)
    - get proxied IP instead of proxy IP
    - log referer for redirect and failed requests
    - log user-agent for failed requests
    - record per-request metrics in prometheus
    """
    status = handler.get_status()
    request = handler.request
    request_time = 1000.0 * request.request_time()  # seconds to milliseconds

    if status == 304 or (
        status < 300
        and (
            isinstance(handler, StaticFileHandler)
            or getattr(handler, "log_success_debug", False)
        )
    ):
        # static-file success and 304 Found are debug-level
        log_level = logging.DEBUG
    elif status < 400:
        log_level = logging.INFO
    elif status < 500:
        log_level = logging.WARNING
    else:
        log_level = logging.ERROR

    if request_time >= 1000 and log_level < logging.INFO:
        # slow responses are always logged at least INFO-level
        log_level = logging.INFO

    uri = _scrub_uri(request.uri)
    headers = _scrub_headers(request.headers)

    try:
        user = handler.current_user
    except (HTTPError, RuntimeError):
        username = ""
    else:
        if user is None:
            username = ""
        elif isinstance(user, str):
            username = user
        elif isinstance(user, dict):
            username = user.get("name", "unknown")
        else:
            username = "unknown"

    ns = dict(
        status=status,
        method=request.method,
        ip=request.remote_ip,
        uri=uri,
        request_time=request_time,
        user=username,
        location="",
    )
    msg = "{status} {method} {uri}{location} ({user}@{ip}) {request_time:.2f}ms"
    if status >= 500 and status not in {502, 503}:
        access_log.log(log_level, json.dumps(headers, indent=2))
    elif status in {301, 302}:
        # log redirect targets
        # FIXME: _headers is private, but there doesn't appear to be a public way
        # to get headers from tornado
        location = handler._headers.get("Location")
        if location:
            ns["location"] = f" -> {_scrub_uri(location)}"
    access_log.log(log_level, msg.format(**ns))
log a bit more information about each request than tornado's default

    - move static file get success to debug-level (reduces noise)
    - get proxied IP instead of proxy IP
    - log referer for redirect and failed requests
    - log user-agent for failed requests
    - record per-request metrics in prometheus
    
binderhub/log.py