2009-11-25 Yuzo Fujishima <yuzo@google.com>
[WebKit-https.git] / WebKitTools / pywebsocket / mod_pywebsocket / standalone.py
index a4c142b4151d497f576c2e35d73239636f8514cb..3b2d0dc95b861e306988c1f1309adb88639409a4 100644 (file)
@@ -38,6 +38,7 @@ Usage:
     python standalone.py [-p <ws_port>] [-w <websock_handlers>]
                          [-s <scan_dir>]
                          [-d <document_root>]
+                         ... for other options, see _main below ...
 
 <ws_port> is the port number to use for ws:// connection.
 
@@ -59,6 +60,7 @@ import BaseHTTPServer
 import SimpleHTTPServer
 import SocketServer
 import logging
+import logging.handlers
 import optparse
 import os
 import socket
@@ -75,6 +77,24 @@ import dispatch
 import handshake
 
 
+_LOG_LEVELS = {
+    'debug': logging.DEBUG,
+    'info': logging.INFO,
+    'warn': logging.WARN,
+    'error': logging.ERROR,
+    'critical': logging.CRITICAL};
+
+_DEFAULT_LOG_MAX_BYTES = 1024 * 256
+_DEFAULT_LOG_BACKUP_COUNT = 5
+
+
+def _print_warnings_if_any(dispatcher):
+    warnings = dispatcher.source_warnings()
+    if warnings:
+        for warning in warnings:
+            logging.warning('mod_pywebsocket: %s' % warning)
+
+
 class _StandaloneConnection(object):
     """Mimic mod_python mp_conn."""
 
@@ -152,6 +172,7 @@ class WebSocketServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
             socket_ = OpenSSL.SSL.Connection(ctx, socket_)
         return socket_
 
+
 class WebSocketRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
     """SimpleHTTPRequestHandler specialized for Web Socket."""
 
@@ -159,15 +180,13 @@ class WebSocketRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
         """Override SocketServer.StreamRequestHandler.setup."""
 
         self.connection = self.request
-        self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
-        self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
+        self.rfile = socket._fileobject(self.request, 'rb', self.rbufsize)
+        self.wfile = socket._fileobject(self.request, 'wb', self.wbufsize)
 
     def __init__(self, *args, **keywords):
         self._request = _StandaloneRequest(
                 self, WebSocketRequestHandler.options.use_tls)
-        self._dispatcher = dispatch.Dispatcher(
-                WebSocketRequestHandler.options.websock_handlers,
-                WebSocketRequestHandler.options.scan_dir)
+        self._dispatcher = WebSocketRequestHandler.options.dispatcher
         self._print_warnings_if_any()
         self._handshaker = handshake.Handshaker(self._request,
                                                 self._dispatcher)
@@ -200,10 +219,35 @@ class WebSocketRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
                 return False
         return result
 
+    def log_request(self, code='-', size='-'):
+        """Override BaseHTTPServer.log_request."""
+
+        logging.info('"%s" %s %s',
+                     self.requestline, str(code), str(size))
+
+    def log_error(self, *args):
+        """Override BaseHTTPServer.log_error."""
+
+        # Despite the name, this method is for warnings than for errors.
+        # For example, HTTP status code is logged by this method.
+        logging.warn('%s - %s' % (self.address_string(), (args[0] % args[1:])))
 
-def _main():
-    logging.basicConfig()
 
+def _configure_logging(options):
+    logger = logging.getLogger()
+    logger.setLevel(_LOG_LEVELS[options.log_level])
+    if options.log_file:
+        handler = logging.handlers.RotatingFileHandler(
+                options.log_file, 'a', options.log_max, options.log_count)
+    else:
+        handler = logging.StreamHandler()
+    formatter = logging.Formatter(
+            "[%(asctime)s] [%(levelname)s] %(name)s: %(message)s")
+    handler.setFormatter(formatter)
+    logger.addHandler(handler)
+
+
+def _main():
     parser = optparse.OptionParser()
     parser.add_option('-p', '--port', dest='port', type='int',
                       default=handshake._DEFAULT_WEB_SOCKET_PORT,
@@ -224,27 +268,51 @@ def _main():
                       default='', help='TLS private key file.')
     parser.add_option('-c', '--certificate', dest='certificate',
                       default='', help='TLS certificate file.')
+    parser.add_option('-l', '--log_file', dest='log_file',
+                      default='', help='Log file.')
+    parser.add_option('--log_level', type='choice', dest='log_level',
+                      default='warn',
+                      choices=['debug', 'info', 'warn', 'error', 'critical'],
+                      help='Log level.')
+    parser.add_option('--log_max', dest='log_max', type='int',
+                      default=_DEFAULT_LOG_MAX_BYTES,
+                      help='Log maximum bytes')
+    parser.add_option('--log_count', dest='log_count', type='int',
+                      default=_DEFAULT_LOG_BACKUP_COUNT,
+                      help='Log backup count')
     options = parser.parse_args()[0]
 
+    os.chdir(options.document_root)
+
+    _configure_logging(options)
+
     if options.use_tls:
         if not _HAS_OPEN_SSL:
-            print >>sys.stderr, 'To use TLS, install pyOpenSSL.'
+            logging.critical('To use TLS, install pyOpenSSL.')
             sys.exit(1)
         if not options.private_key or not options.certificate:
-            print >>sys.stderr, ('To use TLS, specify private_key and '
-                                 'certificate.')
+            logging.critical(
+                    'To use TLS, specify private_key and certificate.')
             sys.exit(1)
 
     if not options.scan_dir:
         options.scan_dir = options.websock_handlers
 
-    WebSocketRequestHandler.options = options
-    WebSocketServer.options = options
-
-    os.chdir(options.document_root)
-
-    server = WebSocketServer(('', options.port), WebSocketRequestHandler)
-    server.serve_forever()
+    try:
+        # Share a Dispatcher among request handlers to save time for
+        # instantiation.  Dispatcher can be shared because it is thread-safe.
+        options.dispatcher = dispatch.Dispatcher(options.websock_handlers,
+                                                 options.scan_dir)
+        _print_warnings_if_any(options.dispatcher)
+
+        WebSocketRequestHandler.options = options
+        WebSocketServer.options = options
+
+        server = WebSocketServer(('', options.port), WebSocketRequestHandler)
+        server.serve_forever()
+    except Exception, e:
+        logging.critical(str(e))
+        sys.exit(1)
 
 
 if __name__ == '__main__':