[project @ Arch-1:robey@lag.net--2003-public%secsh--dev--1.0--patch-140]

more flexible logging
some tweaks to make channels etc follow the logger setting of their parent
transport, so that setting the log channel for a paramiko transport will
cause all sub-logging to branch out from that channel.

also, close all open file handles when the sftp server ends.
This commit is contained in:
Robey Pointer 2005-01-17 10:09:09 +00:00
parent 3db675d1be
commit 8878a5f3c2
6 changed files with 55 additions and 10 deletions

View File

@ -281,7 +281,7 @@ class Channel (object):
@type name: str @type name: str
""" """
self.name = name self.name = name
self.logger = logging.getLogger('paramiko.chan.' + name) self.logger = logging.getLogger(self.transport.get_log_channel() + '.' + self.name)
def get_name(self): def get_name(self):
""" """
@ -758,6 +758,7 @@ class Channel (object):
def _set_transport(self, transport): def _set_transport(self, transport):
self.transport = transport self.transport = transport
self.logger = logging.getLogger(self.transport.get_log_channel() + '.' + self.name)
def _set_window(self, window_size, max_packet_size): def _set_window(self, window_size, max_packet_size):
self.in_window_size = window_size self.in_window_size = window_size

View File

@ -78,6 +78,9 @@ class SFTPAttributes (object):
return attr return attr
from_stat = classmethod(from_stat) from_stat = classmethod(from_stat)
def __repr__(self):
return '<SFTPAttributes: %s>' % self._debug_str()
### internals... ### internals...
@ -138,6 +141,22 @@ class SFTPAttributes (object):
msg.add_string(val) msg.add_string(val)
return return
def _debug_str(self):
out = '[ '
if hasattr(self, 'st_size'):
out += 'size=%d ' % self.st_size
if hasattr(self, 'st_uid') or hasattr(self, 'st_gid'):
out += 'uid=%d gid=%d ' % (getattr(self, 'st_uid', 0), getattr(self, 'st_gid', 0))
if hasattr(self, 'st_mode'):
out += 'mode=%d ' % self.st_mode
if hasattr(self, 'st_atime') or hasattr(self, 'st_mtime'):
out += 'atime=%d mtime=%d ' % (getattr(self, 'st_atime', 0),
getattr(self, 'st_mtime', 0))
for k, v in self.attr.iteritems():
out += '"%s"=%s ' % (str(k), repr(v))
out += ']'
return out
def _rwx(n, suid, sticky=False): def _rwx(n, suid, sticky=False):
if suid: if suid:
suid = 2 suid = 2

View File

@ -50,7 +50,9 @@ class SFTPClient (BaseSFTP):
self.request_number = 1 self.request_number = 1
if type(sock) is Channel: if type(sock) is Channel:
# override default logger # override default logger
self.logger = logging.getLogger('paramiko.chan.' + sock.get_name() + '.sftp') transport = self.sock.get_transport()
self.logger = logging.getLogger(transport.get_log_channel() + '.' +
self.sock.get_name() + '.sftp')
self._send_version() self._send_version()
def from_transport(selfclass, t): def from_transport(selfclass, t):

View File

@ -29,9 +29,9 @@ from sftp import *
class SFTPHandle (object): class SFTPHandle (object):
""" """
Abstract object representing a handle to an open file (or folder) on Abstract object representing a handle to an open file (or folder) in an
the server. Each handle has a string representation used by the client SFTP server implementation. Each handle has a string representation used
to refer to the underlying file. by the client to refer to the underlying file.
Server implementations can (and should) subclass SFTPHandle to implement Server implementations can (and should) subclass SFTPHandle to implement
features of a file handle, like L{stat} or L{chattr}. features of a file handle, like L{stat} or L{chattr}.
@ -138,7 +138,7 @@ class SFTPHandle (object):
it's called on an open file instead of a path. it's called on an open file instead of a path.
@return: an attributes object for the given file, or an SFTP error @return: an attributes object for the given file, or an SFTP error
code (like L{SFTP_PERMISSION_DENIED}). code (like L{SFTP_PERMISSION_DENIED}).
@rtype: L{SFTPAttributes} I{or error code} @rtype: L{SFTPAttributes} I{or error code}
""" """
return SFTP_OP_UNSUPPORTED return SFTP_OP_UNSUPPORTED

View File

@ -58,7 +58,9 @@ class SFTPServer (BaseSFTP, SubsystemHandler):
BaseSFTP.__init__(self) BaseSFTP.__init__(self)
SubsystemHandler.__init__(self, channel, name) SubsystemHandler.__init__(self, channel, name)
self.ultra_debug = True self.ultra_debug = True
self.logger = logging.getLogger('paramiko.chan.' + channel.get_name() + '.sftp') transport = channel.get_transport()
self.logger = logging.getLogger(transport.get_log_channel() + '.' +
channel.get_name() + '.sftp')
self.next_handle = 1 self.next_handle = 1
# map of handle-string to SFTPHandle for files & folders: # map of handle-string to SFTPHandle for files & folders:
self.file_table = { } self.file_table = { }
@ -88,6 +90,13 @@ class SFTPServer (BaseSFTP, SubsystemHandler):
def finish_subsystem(self): def finish_subsystem(self):
self.server.session_ended() self.server.session_ended()
# close any file handles that were left open (so we can return them to the OS quickly)
for f in self.file_table.itervalues():
f.close()
for f in self.folder_table.itervalues():
f.close()
self.file_table = {}
self.folder_table = {}
def convert_errno(e): def convert_errno(e):
""" """
@ -121,7 +130,7 @@ class SFTPServer (BaseSFTP, SubsystemHandler):
requests into local file operations. requests into local file operations.
@param filename: name of the file to alter (should usually be an @param filename: name of the file to alter (should usually be an
absolute path). absolute path).
@type filename: str @type filename: str
@param attr: attributes to change. @param attr: attributes to change.
@type attr: L{SFTPAttributes} @type attr: L{SFTPAttributes}

View File

@ -237,12 +237,13 @@ class BaseTransport (threading.Thread):
self.channels = { } # (id -> Channel) self.channels = { } # (id -> Channel)
self.channel_events = { } # (id -> Event) self.channel_events = { } # (id -> Event)
self.channel_counter = 1 self.channel_counter = 1
self.logger = logging.getLogger('paramiko.transport')
self.window_size = 65536 self.window_size = 65536
self.max_packet_size = 32768 self.max_packet_size = 32768
self.ultra_debug = False self.ultra_debug = False
self.saved_exception = None self.saved_exception = None
self.clear_to_send = threading.Event() self.clear_to_send = threading.Event()
self.log_name = 'paramiko.transport'
self.logger = logging.getLogger(self.log_name)
# used for noticing when to re-key: # used for noticing when to re-key:
self.received_bytes = 0 self.received_bytes = 0
self.received_packets = 0 self.received_packets = 0
@ -783,15 +784,28 @@ class BaseTransport (threading.Thread):
""" """
Set the channel for this transport's logging. The default is Set the channel for this transport's logging. The default is
C{"paramiko.transport"} but it can be set to anything you want. C{"paramiko.transport"} but it can be set to anything you want.
(See the C{logging} module for more info.) (See the C{logging} module for more info.) SSH Channels will log
to a sub-channel of the one specified.
@param name: new channel name for logging. @param name: new channel name for logging.
@type name: str @type name: str
@since: 1.1 @since: 1.1
""" """
self.log_name = name
self.logger = logging.getLogger(name) self.logger = logging.getLogger(name)
def get_log_channel(self):
"""
Return the channel name used for this transport's logging.
@return: channel name.
@rtype: str
@since: 1.2
"""
return self.log_name
### internals... ### internals...