def __init__( self, app, excluded_urls=None, default_span_details=None, server_request_hook: _ServerRequestHookT = None, client_request_hook: _ClientRequestHookT = None, client_response_hook: _ClientResponseHookT = None, tracer_provider=None, meter_provider=None, ): self.app = guarantee_single_callable(app) self.tracer = trace.get_tracer(__name__, __version__, tracer_provider) self.meter = get_meter(__name__, __version__, meter_provider) self.duration_histogram = self.meter.create_histogram( name="http.server.duration", unit="ms", description="measures the duration of the inbound HTTP request", ) self.active_requests_counter = self.meter.create_up_down_counter( name="http.server.active_requests", unit="requests", description="measures the number of concurrent HTTP requests that are currently in-flight", ) self.excluded_urls = excluded_urls self.default_span_details = ( default_span_details or get_default_span_details ) self.server_request_hook = server_request_hook self.client_request_hook = client_request_hook self.client_response_hook = client_response_hook
def __init__(self, app, excluded_urls=None, span_details_callback=None): self.app = guarantee_single_callable(app) self.tracer = trace.get_tracer(__name__, __version__) self.span_details_callback = ( span_details_callback or get_default_span_details ) self.excluded_urls = excluded_urls
async def __call__(self, scope, receive, send): if scope["type"] in self.application_mapping: application = guarantee_single_callable( self.application_mapping[scope["type"]]) return await application(scope, receive, send) else: raise ValueError("No application configured for scope type %r" % scope["type"])
def prepare_application(self, application: Any) -> Any: # Convert an WSGI-App to an ASGI-App if needed. signature = inspect.signature(application, follow_wrapped=True) if len(signature.parameters) == 2: application = WsgiContainer(application) # Convert an ASGI2-App to ASGI3 from asgiref.compatibility import guarantee_single_callable application = guarantee_single_callable(application) return application
async def __call__(self, scope, receive, send): if "channel" not in scope: raise ValueError( "ChannelNameRouter got a scope without a 'channel' key. " + "Did you make sure it's only being used for 'channel' type messages?" ) if scope["channel"] in self.application_mapping: application = guarantee_single_callable( self.application_mapping[scope["channel"]]) return await application(scope, receive, send) else: raise ValueError("No application configured for channel name %r" % scope["channel"])
def __init__( self, app, excluded_urls=None, default_span_details=None, server_request_hook: _ServerRequestHookT = None, client_request_hook: _ClientRequestHookT = None, client_response_hook: _ClientResponseHookT = None, tracer_provider=None, ): self.app = guarantee_single_callable(app) self.tracer = trace.get_tracer(__name__, __version__, tracer_provider) self.excluded_urls = excluded_urls self.default_span_details = (default_span_details or get_default_span_details) self.server_request_hook = server_request_hook self.client_request_hook = client_request_hook self.client_response_hook = client_response_hook
async def __call__(self, scope, receive, send): # Get the path path = scope.get("path_remaining", scope.get("path", None)) if path is None: raise ValueError( "No 'path' key in connection scope, cannot route URLs") # Remove leading / to match Django's handling path = path.lstrip("/") # Run through the routes we have until one matches for route in self.routes: try: match = route_pattern_match(route, path) if match: new_path, args, kwargs = match # Add args or kwargs into the scope outer = scope.get("url_route", {}) application = guarantee_single_callable(route.callback) return await application( dict( scope, path_remaining=new_path, url_route={ "args": outer.get("args", ()) + args, "kwargs": { **outer.get("kwargs", {}), **kwargs }, }, ), receive, send, ) except Resolver404: pass else: if "path_remaining" in scope: raise Resolver404("No route found for path %r." % path) # We are the outermost URLRouter raise ValueError("No route found for path %r." % path)
def __init__(self, app): self.app = guarantee_single_callable(app)
def run(self, args): """ Pass in raw argument list and it will decode them and run the server. """ # Decode args args = self.parser.parse_args(args) # Set up logging logging.basicConfig( level={ 0: logging.WARN, 1: logging.INFO, 2: logging.DEBUG, 3: logging.DEBUG, # Also turns on asyncio debug }[args.verbosity], format="%(asctime)-15s %(levelname)-8s %(message)s", ) # If verbosity is 1 or greater, or they told us explicitly, set up access log access_log_stream = None if args.access_log: if args.access_log == "-": access_log_stream = sys.stdout else: access_log_stream = open(args.access_log, "a", 1) elif args.verbosity >= 1: access_log_stream = sys.stdout # Import application sys.path.insert(0, ".") application = import_by_path(args.application) application = guarantee_single_callable(application) # Set up port/host bindings if not any([ args.host, args.port is not None, args.unix_socket, args.file_descriptor is not None, args.socket_strings, ]): # no advanced binding options passed, patch in defaults args.host = DEFAULT_HOST args.port = DEFAULT_PORT elif args.host and args.port is None: args.port = DEFAULT_PORT elif args.port is not None and not args.host: args.host = DEFAULT_HOST # Build endpoint description strings from (optional) cli arguments endpoints = build_endpoint_description_strings( host=args.host, port=args.port, unix_socket=args.unix_socket, file_descriptor=args.file_descriptor, ) endpoints = sorted(args.socket_strings + endpoints) # Start the server logger.info("Starting server at {}".format(", ".join(endpoints))) self.server = self.server_class( application=application, endpoints=endpoints, http_timeout=args.http_timeout, ping_interval=args.ping_interval, ping_timeout=args.ping_timeout, websocket_timeout=args.websocket_timeout, websocket_connect_timeout=args.websocket_connect_timeout, websocket_handshake_timeout=args.websocket_connect_timeout, application_close_timeout=args.application_close_timeout, action_logger=AccessLogGenerator(access_log_stream) if access_log_stream else None, ws_protocols=args.ws_protocols, root_path=args.root_path, verbosity=args.verbosity, proxy_forwarded_address_header=self._get_forwarded_host(args=args), proxy_forwarded_port_header=self._get_forwarded_port(args=args), proxy_forwarded_proto_header="X-Forwarded-Proto" if args.proxy_headers else None, server_name=args.server_name, ) self.server.run()
# Check if header has multiple values, and use the first one return client_ip.split(", ")[0] def log(self, scope: Scope, content_length: int, runtime: float, **kwargs): """Outpot access logs in a structured format""" host = self._get_ip(scope) query_string = "" if scope.get("query_string", b"") != b"": query_string = f"?{scope.get('query_string').decode()}" LOGGER.info( f"{scope.get('path', '')}{query_string}", host=host, method=scope.get("method", ""), scheme=scope.get("scheme", ""), status=self.status_code, size=content_length / 1000 if content_length > 0 else 0, runtime=runtime, **kwargs, ) application = ASGILogger( guarantee_single_callable( SentryAsgiMiddleware( ProtocolTypeRouter({ "http": get_asgi_application(), "websocket": URLRouter(websocket.websocket_urlpatterns), }))))
def __init__(self, app, name_callback=None): self.app = guarantee_single_callable(app) self.tracer = trace.get_tracer(__name__, __version__) self.name_callback = name_callback or get_default_span_name