Do much more runserver-like logging

This commit is contained in:
Andrew Godwin 2016-02-10 20:26:56 +00:00
parent fee6a38483
commit 41b6750afb
2 changed files with 78 additions and 9 deletions

View File

@ -10,6 +10,7 @@ from threading import Lock
from django import http from django import http
from django.core import signals from django.core import signals
from django.core.handlers import base from django.core.handlers import base
from django.core.management.color import color_style
from django.core.urlresolvers import set_script_prefix from django.core.urlresolvers import set_script_prefix
from django.utils import six from django.utils import six
from django.utils.functional import cached_property from django.utils.functional import cached_property

View File

@ -1,7 +1,12 @@
import datetime
import sys
import threading import threading
from django.conf import settings
from django.core.management.commands.runserver import \ from django.core.management.commands.runserver import \
Command as RunserverCommand Command as RunserverCommand
from django.utils import six
from django.utils.encoding import get_system_encoding
from channels import DEFAULT_CHANNEL_LAYER, channel_layers from channels import DEFAULT_CHANNEL_LAYER, channel_layers
from channels.handler import ViewConsumer from channels.handler import ViewConsumer
@ -21,21 +26,84 @@ class Command(RunserverCommand):
self.channel_layer = channel_layers[DEFAULT_CHANNEL_LAYER] self.channel_layer = channel_layers[DEFAULT_CHANNEL_LAYER]
if not self.channel_layer.registry.consumer_for_channel("http.request"): if not self.channel_layer.registry.consumer_for_channel("http.request"):
self.channel_layer.registry.add_consumer(ViewConsumer(), ["http.request"]) self.channel_layer.registry.add_consumer(ViewConsumer(), ["http.request"])
# Run checks
self.stdout.write("Performing system checks...\n\n")
self.check(display_num_errors=True)
self.check_migrations()
# Print helpful text
quit_command = 'CTRL-BREAK' if sys.platform == 'win32' else 'CONTROL-C'
now = datetime.datetime.now().strftime('%B %d, %Y - %X')
if six.PY2:
now = now.decode(get_system_encoding())
self.stdout.write(now)
self.stdout.write((
"Django version %(version)s, using settings %(settings)r\n"
"Starting Channels development server at http://%(addr)s:%(port)s/\n"
"Quit the server with %(quit_command)s.\n"
) % {
"version": self.get_version(),
"settings": settings.SETTINGS_MODULE,
"addr": '[%s]' % self.addr if self._raw_ipv6 else self.addr,
"port": self.port,
"quit_command": quit_command,
})
# Launch worker as subthread # Launch worker as subthread
worker = WorkerThread(self.channel_layer, self.logger) worker = WorkerThread(self.channel_layer, self.logger)
worker.daemon = True worker.daemon = True
worker.start() worker.start()
# Launch server in 'main' thread. Signals are disabled as it's still # Launch server in 'main' thread. Signals are disabled as it's still
# actually a subthread under the autoreloader. # actually a subthread under the autoreloader.
self.logger.info("Daphne running, listening on %s:%s", self.addr, self.port) self.logger.debug("Daphne running, listening on %s:%s", self.addr, self.port)
try:
from daphne.server import Server from daphne.server import Server
Server( Server(
channel_layer=self.channel_layer, channel_layer=self.channel_layer,
host=self.addr, host=self.addr,
port=int(self.port), port=int(self.port),
signal_handlers=False, signal_handlers=False,
action_logger=self.log_action,
).run() ).run()
except KeyboardInterrupt:
shutdown_message = options.get('shutdown_message', '')
if shutdown_message:
self.stdout.write(shutdown_message)
return
def log_action(self, protocol, action, details):
"""
Logs various different kinds of requests to the console.
"""
# All start with timestamp
msg = "[%s] " % datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")
# HTTP requests
if protocol == "http" and action == "complete":
msg += "HTTP %(method)s %(path)s %(status)s [%(client)s]\n" % details
# Utilize terminal colors, if available
if 200 <= details['status'] < 300:
# Put 2XX first, since it should be the common case
msg = self.style.HTTP_SUCCESS(msg)
elif 100 <= details['status'] < 200:
msg = self.style.HTTP_INFO(msg)
elif details['status'] == 304:
msg = self.style.HTTP_NOT_MODIFIED(msg)
elif 300 <= details['status'] < 400:
msg = self.style.HTTP_REDIRECT(msg)
elif details['status'] == 404:
msg = self.style.HTTP_NOT_FOUND(msg)
elif 400 <= details['status'] < 500:
msg = self.style.HTTP_BAD_REQUEST(msg)
else:
# Any 5XX, or any other response
msg = self.style.HTTP_SERVER_ERROR(msg)
# Websocket requests
elif protocol == "websocket" and action == "connected":
msg += "WebSocket CONNECT %(path)s [%(client)s]\n" % details
elif protocol == "websocket" and action == "disconnected":
msg += "WebSocket DISCONNECT %(path)s [%(client)s]\n" % details
sys.stderr.write(msg)
class WorkerThread(threading.Thread): class WorkerThread(threading.Thread):
""" """
@ -48,6 +116,6 @@ class WorkerThread(threading.Thread):
self.logger = logger self.logger = logger
def run(self): def run(self):
self.logger.info("Worker thread running") self.logger.debug("Worker thread running")
worker = Worker(channel_layer=self.channel_layer) worker = Worker(channel_layer=self.channel_layer)
worker.run() worker.run()