diff --git a/daphne/http_protocol.py b/daphne/http_protocol.py index 31b1431..0a34deb 100755 --- a/daphne/http_protocol.py +++ b/daphne/http_protocol.py @@ -132,6 +132,12 @@ class WebRequest(http.Request): logger.debug("HTTP %s response for %s", message['status'], self.reply_channel) else: logger.debug("HTTP %s response chunk for %s", message['status'], self.reply_channel) + self.factory.log_action("http", "complete", { + "path": self.path.decode("ascii"), + "status": message['status'], + "method": self.method.decode("ascii"), + "client": "%s:%s" % (self.client.host, self.client.port), + }) class HTTPProtocol(http.HTTPChannel): @@ -149,9 +155,10 @@ class HTTPFactory(http.HTTPFactory): protocol = HTTPProtocol - def __init__(self, channel_layer): + def __init__(self, server): http.HTTPFactory.__init__(self) - self.channel_layer = channel_layer + self.channel_layer = server.channel_layer + self.action_logger = server.action_logger # We track all sub-protocols for response channel mapping self.reply_protocols = {} # Make a factory for WebSocket protocols @@ -174,3 +181,10 @@ class HTTPFactory(http.HTTPFactory): self.reply_protocols[channel].serverClose() else: raise ValueError("Cannot dispatch message on channel %r" % channel) + + def log_action(self, protocol, action, details): + """ + Dispatches to any registered action logger, if there is one. + """ + if self.action_logger: + self.action_logger(protocol, action, details) diff --git a/daphne/server.py b/daphne/server.py index 7615959..076b652 100755 --- a/daphne/server.py +++ b/daphne/server.py @@ -6,14 +6,15 @@ from .http_protocol import HTTPFactory class Server(object): - def __init__(self, channel_layer, host="127.0.0.1", port=8000, signal_handlers=True): + def __init__(self, channel_layer, host="127.0.0.1", port=8000, signal_handlers=True, action_logger=None): self.channel_layer = channel_layer self.host = host self.port = port self.signal_handlers = signal_handlers + self.action_logger = action_logger def run(self): - self.factory = HTTPFactory(self.channel_layer) + self.factory = HTTPFactory(self) reactor.listenTCP(self.port, self.factory, interface=self.host) reactor.callInThread(self.backend_reader) reactor.run(installSignalHandlers=self.signal_handlers) diff --git a/daphne/ws_protocol.py b/daphne/ws_protocol.py index 1757e13..8abdf44 100755 --- a/daphne/ws_protocol.py +++ b/daphne/ws_protocol.py @@ -21,6 +21,7 @@ class WebSocketProtocol(WebSocketServerProtocol): self.channel_layer = self.main_factory.channel_layer def onConnect(self, request): + self.request = request try: # Sanitize and decode headers clean_headers = {} @@ -55,6 +56,10 @@ class WebSocketProtocol(WebSocketServerProtocol): # Send news that this channel is open logger.debug("WebSocket open for %s", self.reply_channel) self.channel_layer.send("websocket.connect", self.request_info) + self.factory.log_action("websocket", "connected", { + "path": self.request.path, + "client": "%s:%s" % (self.transport.getPeer().host, self.transport.getPeer().port), + }) def onMessage(self, payload, isBinary): logger.debug("WebSocket incoming packet on %s", self.reply_channel) @@ -92,6 +97,10 @@ class WebSocketProtocol(WebSocketServerProtocol): self.channel_layer.send("websocket.disconnect", { "reply_channel": self.reply_channel, }) + self.factory.log_action("websocket", "disconnected", { + "path": self.request.path, + "client": "%s:%s" % (self.transport.getPeer().host, self.transport.getPeer().port), + }) else: logger.debug("WebSocket closed before handshake established") @@ -106,3 +115,6 @@ class WebSocketFactory(WebSocketServerFactory): def __init__(self, main_factory, *args, **kwargs): self.main_factory = main_factory WebSocketServerFactory.__init__(self, *args, **kwargs) + + def log_action(self, *args, **kwargs): + self.main_factory.log_action(*args, **kwargs)