[Zope-Checkins] CVS: ZODB3/ZEO - DebugServer.py:1.1 runsvr.py:1.30

Jeremy Hylton jeremy@zope.com
Wed, 15 Jan 2003 16:26:56 -0500


Update of /cvs-repository/ZODB3/ZEO
In directory cvs.zope.org:/tmp/cvs-serv21452/ZEO

Modified Files:
	runsvr.py 
Added Files:
	DebugServer.py 
Log Message:
Add minimal progress on debugger/recorder for ZEO.

Handing off to Barry.


=== Added File ZODB3/ZEO/DebugServer.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""A debugging version of the server that records network activity."""

from __future__ import nested_scopes

import struct
import time

from ZEO.StorageServer import StorageServer, ZEOStorage, log
from ZEO.zrpc.server import ManagedServerConnection

# a bunch of codes
NEW_CONN = 1
CLOSE_CONN = 2
DATA = 3
ERROR = 4

class DebugManagedServerConnection(ManagedServerConnection):
    
    def __init__(self, sock, addr, obj, mgr):
        # mgr is the DebugServer instance
        self.mgr = mgr
        self.__super_init(sock, addr, obj)
        record_id = mgr._record_connection(addr)
        self._record = lambda code, data: mgr._record(record_id, code, data)
        self.obj.notifyConnected(self)

    def close(self):
        self._record(CLOSE_CONN, "")
        ManagedServerConnection.close(self)

    # override the lowest-level of asyncore's connection

    def recv(self, buffer_size):
        try:
            data = self.socket.recv(buffer_size)
            if not data:
                # a closed connection is indicated by signaling
                # a read condition, and having recv() return 0.
                self.handle_close()
                return ''
            else:
                self._record(DATA, data)
                return data
        except socket.error, why:
            # winsock sometimes throws ENOTCONN
            self._record(ERROR, why)
            if why[0] in [ECONNRESET, ENOTCONN, ESHUTDOWN]:
                self.handle_close()
                return ''
            else:
                raise socket.error, why

class DebugServer(StorageServer):

    ZEOStorageClass = DebugZEOStorage
    ManagedServerConnectionClass = DebugManagerConnection
    
    def __init__(self, *args, **kwargs):
        StorageServer.__init__(*args, **kwargs)
        self._setup_record(kwargs["record"])
        self._conn_counter = 1

    def _setup_record(self, path):
        try:
            self._recordfile = open(path, "ab")
        except IOError, msg:
            self._recordfile = None
            log("failed to open recordfile %s: %s" % (path, msg))

    def _record_connection(self, addr):
        cid = self._conn_counter
        self._conn_counter += 1
        self._record(cid, NEW_CONN, str(addr))
        return cid

    def _record(self, conn, code, data):
        s = struct.pack(">iii", code, time.time(), len(data)) + data
        self._recordfile.write(s)


=== ZODB3/ZEO/runsvr.py 1.29 => 1.30 ===
--- ZODB3/ZEO/runsvr.py:1.29	Fri Jan 10 13:38:02 2003
+++ ZODB3/ZEO/runsvr.py	Wed Jan 15 16:26:53 2003
@@ -23,6 +23,7 @@
 -f/--filename FILENAME -- filename for FileStorage
 -h/--help -- print this usage message and exit
 -m/--monitor ADDRESS -- address of monitor server
+-r/--record -- path of file to record low-level network activity
 
 Unless -C is specified, -a and -f are required.
 """
@@ -176,18 +177,20 @@
     transaction_timeout = None
     invalidation_queue_size = None
     monitor_address = None
+    record = None
 
     family = None                       # set by -a; AF_UNIX or AF_INET
     address = None                      # set by -a; string or (host, port)
     storages = None                     # set by -f
 
-    _short_options = "a:C:f:hm:"
+    _short_options = "a:C:f:hm:r:"
     _long_options = [
         "address=",
         "configuration=",
         "filename=",
         "help",
         "monitor=",
+        "record=",
         ]
 
     def handle_option(self, opt, arg):
@@ -225,6 +228,8 @@
             key = str(1 + len(self.storages))
             conf = FSConfig(key, arg)
             self.storages[key] = FileStorage(conf)
+        elif opt in ("-r", "--record"):
+            self.record = arg
         else:
             # Pass it to the base class, for --help/-h
             Options.handle_option(self, opt, arg)