From b772a26680895ecf102b524444623fc10c4d183d Mon Sep 17 00:00:00 2001 From: Sam Thursfield Date: Wed, 9 Apr 2014 14:02:04 +0000 Subject: distbuild: Improve logging of connections and objects New DistbuildSocket class that wraps socket.socket(), providing a descriptive repr() handler showing where the socket is connected, and providing a couple of helper methods for fetching local and remote endpoint names. This commit also adds a descriptive repr() handler to a few other objects (mostly giving socket connection details). --- distbuild-helper | 2 +- distbuild/__init__.py | 2 ++ distbuild/build_controller.py | 4 +++ distbuild/connection_machine.py | 2 +- distbuild/distbuild_socket.py | 63 +++++++++++++++++++++++++++++++++++++++ distbuild/initiator_connection.py | 4 +++ distbuild/jm.py | 6 +++- distbuild/sockbuf.py | 4 +++ distbuild/socketsrc.py | 13 +++++--- distbuild/sockserv.py | 2 +- 10 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 distbuild/distbuild_socket.py diff --git a/distbuild-helper b/distbuild-helper index 7399fb59..08e30f10 100755 --- a/distbuild-helper +++ b/distbuild-helper @@ -309,7 +309,7 @@ class DistributedBuildHelper(cliapp.Application): addr = self.settings['parent-address'] port = self.settings['parent-port'] - conn = socket.socket() + conn = distbuild.create_socket() conn.connect((addr, port)) helper = HelperMachine(conn) helper.debug_messages = self.settings['debug-messages'] diff --git a/distbuild/__init__.py b/distbuild/__init__.py index 3e60d5ee..57aaccaf 100644 --- a/distbuild/__init__.py +++ b/distbuild/__init__.py @@ -58,4 +58,6 @@ from protocol import message from crashpoint import (crash_point, add_crash_condition, add_crash_conditions, clear_crash_conditions) +from distbuild_socket import create_socket + __all__ = locals() diff --git a/distbuild/build_controller.py b/distbuild/build_controller.py index 81b03039..ce8fced5 100644 --- a/distbuild/build_controller.py +++ b/distbuild/build_controller.py @@ -160,6 +160,10 @@ class BuildController(distbuild.StateMachine): self._helper_id = None self.debug_transitions = False + def __repr__(self): + return '' % (id(self), + self._request['id']) + def setup(self): distbuild.crash_point() diff --git a/distbuild/connection_machine.py b/distbuild/connection_machine.py index 3d4e8d04..2f768f0b 100644 --- a/distbuild/connection_machine.py +++ b/distbuild/connection_machine.py @@ -97,7 +97,7 @@ class ConnectionMachine(distbuild.StateMachine): logging.debug( 'ConnectionMachine: connecting to %s:%s' % (self._addr, self._port)) - self._socket = socket.socket() + self._socket = distbuild.create_socket() distbuild.set_nonblocking(self._socket) try: self._socket.connect((self._addr, self._port)) diff --git a/distbuild/distbuild_socket.py b/distbuild/distbuild_socket.py new file mode 100644 index 00000000..0408a2c1 --- /dev/null +++ b/distbuild/distbuild_socket.py @@ -0,0 +1,63 @@ +# distbuild/distbuild_socket.py -- wrapper around Python 'socket' module. +# +# Copyright (C) 2014 Codethink Limited +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.. + + +import socket + + +class DistbuildSocket(object): + '''Wraps socket.SocketType with a few helper functions.''' + + def __init__(self, real_socket): + self.real_socket = real_socket + + def __getattr__(self, name): + return getattr(self.real_socket, name) + + def __repr__(self): + return '' % (id(self), str(self)) + + def __str__(self): + localname = self.localname() or '(closed)' + remotename = self.remotename() + if remotename is None: + return '%s' % self.localname() + else: + return '%s -> %s' % (self.localname(), remotename) + + def accept(self, *args): + result = self.real_socket.accept(*args) + return DistbuildSocket(result[0]), result[1:] + + def localname(self): + '''Get local end of socket connection as a string.''' + try: + return '%s:%s' % self.getsockname() + except socket.error: + # If the socket is in destruction we may get EBADF here. + return None + + def remotename(self): + '''Get remote end of socket connection as a string.''' + try: + return '%s:%s' % self.getpeername() + except socket.error: + return None + + +def create_socket(*args): + return DistbuildSocket(socket.socket(*args)) diff --git a/distbuild/initiator_connection.py b/distbuild/initiator_connection.py index 48d083e4..e6202908 100644 --- a/distbuild/initiator_connection.py +++ b/distbuild/initiator_connection.py @@ -52,6 +52,10 @@ class InitiatorConnection(distbuild.StateMachine): self.artifact_cache_server = artifact_cache_server self.morph_instance = morph_instance + def __repr__(self): + remote = self.conn.remotename() + return '' % (id(self), remote) + def setup(self): self.jm = distbuild.JsonMachine(self.conn) self.mainloop.add_state_machine(self.jm) diff --git a/distbuild/jm.py b/distbuild/jm.py index ae222c00..bb86adc4 100644 --- a/distbuild/jm.py +++ b/distbuild/jm.py @@ -43,7 +43,11 @@ class JsonMachine(StateMachine): StateMachine.__init__(self, 'rw') self.conn = conn self.debug_json = False - + + def __repr__(self): + return '' % (id(self), + self.conn, self.max_buffer) + def setup(self): sockbuf = self.sockbuf = SocketBuffer(self.conn, self.max_buffer) self.mainloop.add_state_machine(sockbuf) diff --git a/distbuild/sockbuf.py b/distbuild/sockbuf.py index a7fe339a..6803bfb5 100644 --- a/distbuild/sockbuf.py +++ b/distbuild/sockbuf.py @@ -77,6 +77,10 @@ class SocketBuffer(StateMachine): self._sock = sock self._max_buffer = max_buffer + def __repr__(self): + return '' % ( + id(self), self._sock, self._max_buffer) + def setup(self): src = self._src = SocketEventSource(self._sock) src.stop_writing() # We'll start writing when we need to. diff --git a/distbuild/socketsrc.py b/distbuild/socketsrc.py index 78486f0e..14adc74d 100644 --- a/distbuild/socketsrc.py +++ b/distbuild/socketsrc.py @@ -9,6 +9,8 @@ import logging import os import socket +import distbuild + from eventsrc import EventSource @@ -48,13 +50,13 @@ class ListeningSocketEventSource(EventSource): '''An event source for a socket that listens for connections.''' def __init__(self, addr, port): - self.sock = socket.socket() + self.sock = distbuild.create_socket() self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.sock.bind((addr, port)) self.sock.listen(5) self._accepting = True - logging.info('Listening at %s' % repr(self.sock.getsockname())) - + logging.info('Listening at %s' % self.sock.remotename()) + def get_select_params(self): r = [self.sock.fileno()] if self._accepting else [] return r, [], [], None @@ -117,7 +119,10 @@ class SocketEventSource(EventSource): self._writing = True set_nonblocking(sock) - + + def __repr__(self): + return '' % (id(self), self.sock) + def get_select_params(self): r = [self.sock.fileno()] if self._reading else [] w = [self.sock.fileno()] if self._writing else [] diff --git a/distbuild/sockserv.py b/distbuild/sockserv.py index 6d8f216e..dc313d06 100644 --- a/distbuild/sockserv.py +++ b/distbuild/sockserv.py @@ -34,7 +34,7 @@ class ListenServer(StateMachine): def new_conn(self, event_source, event): logging.debug( 'ListenServer: Creating new %s using %s and %s' % - (repr(self._machine), + (self._machine, repr(event.connection), repr(self._extra_args))) m = self._machine(event.connection, *self._extra_args) -- cgit v1.2.1