Загрузка данных


def get_app(opts):
    """
    Returns a WSGI app and a configuration dictionary
    """
    apiopts = opts.get(__name__.rsplit(".", 2)[-2], {})  # rest_cherrypy opts

    # Add Salt and salt-api config options to the main CherryPy config dict
    cherrypy.config["saltopts"] = opts
    cherrypy.config["apiopts"] = apiopts

    # --- START: ADD CUSTOM LOG FORMAT ---
    # Store username in the request object for later use in logging
    def store_username():
        """Extract username from request and store it in cherrypy.request"""
        if cherrypy.request.method == "POST" and cherrypy.request.path_info == "/run":
            lowstate = getattr(cherrypy.request, "lowstate", None)
            if isinstance(lowstate, list) and lowstate:
                first_chunk = lowstate[0]
                username = first_chunk.get("username")
                if not username and "kwarg" in first_chunk:
                    username = first_chunk["kwarg"].get("username")
                if username:
                    cherrypy.request._salt_username = username
                else:
                    # Check if token auth is used (no username in request)
                    token = first_chunk.get("token")
                    if token:
                        cherrypy.request._salt_username = "token-auth"
                    else:
                        cherrypy.request._salt_username = "-"
            else:
                cherrypy.request._salt_username = "-"
        else:
            cherrypy.request._salt_username = "-"
    
    # Hook into CherryPy's before_handler phase
    cherrypy.tools.store_username = cherrypy.Tool("before_handler", store_username, priority=10)
    
    # Custom log format that includes username
    # %h = remote host, %l = remote logname (always '-'), %u = remote user (we inject this)
    # %t = timestamp, %r = request line, %s = status, %b = bytes, %{Referer}i = referer, %{User-Agent}i = user-agent
    def custom_log_access():
        """Override the default access log format to include username"""
        # Get the default access log format and inject our username
        from cherrypy.lib import httputil
        request = cherrypy.serving.request
        response = cherrypy.serving.response
        
        # Get the username we stored earlier
        username = getattr(request, "_salt_username", "-")
        
        # Build the log line
        remote_host = request.remote.name or request.remote.ip or "-"
        user = username  # This goes in the 'remote user' field
        request_line = "%s %s %s" % (request.method, request.path_info, request.query_string)
        if request.query_string:
            request_line = "%s %s?%s" % (request.method, request.path_info, request.query_string)
        
        # Log using the standard CherryPy access log
        cherrypy.log.access(
            '%s - %s [%s] "%s" %s %s "%s" "%s"' % (
                remote_host,
                user,
                httputil.HTTPDate(),
                request_line,
                response.status,
                response.headers.get("Content-Length") or "-",
                request.headers.get("Referer", "-"),
                request.headers.get("User-Agent", "-"),
            )
        )
        # Prevent duplicate logging
        return False
    
    # Replace the default access log tool
    from cherrypy._cpaccess import AccessTool
    # Disable the default access logger
    cherrypy.tools.access_log = cherrypy.Tool("on_end_request", lambda: None, priority=20)
    # Add our custom access logger
    cherrypy.tools.custom_access_log = cherrypy.Tool("on_end_request", custom_log_access, priority=21)
    
    # Enable our tools in the global config
    cherrypy.config.update({
        "tools.store_username.on": True,
        "tools.custom_access_log.on": True,
    })
    # --- END: ADD CUSTOM LOG FORMAT ---

    root = API()  # cherrypy app
    cpyopts = root.get_conf()  # cherrypy app opts

    return root, apiopts, cpyopts