diff options
-rw-r--r-- | rpki/__init__.py | 28 | ||||
-rw-r--r-- | rpki/config.py | 23 | ||||
-rw-r--r-- | rpki/http.py | 27 | ||||
-rw-r--r-- | rpki/log.py | 15 |
4 files changed, 67 insertions, 26 deletions
diff --git a/rpki/__init__.py b/rpki/__init__.py index 9e090f63..53a32337 100644 --- a/rpki/__init__.py +++ b/rpki/__init__.py @@ -1,2 +1,26 @@ -# This file exists to tell Python that this the content of this -# directory constitute a Python package. +# $Id$ + +# Copyright (C) 2014 Dragon Research Labs ("DRL") +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND DRL DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL DRL BE LIABLE FOR ANY SPECIAL, DIRECT, +# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +# PERFORMANCE OF THIS SOFTWARE. + +# This file exists primarily to tell Python that this the content of +# this directory constitute a Python package, but while we're here, +# create a logger object that programs can use to control logging in +# all of the rpki libraries at once. + +import logging + +logger = logging.getLogger(__name__) + +del logging # Cleanup diff --git a/rpki/config.py b/rpki/config.py index ad87239b..f38427c4 100644 --- a/rpki/config.py +++ b/rpki/config.py @@ -120,20 +120,19 @@ class parser(object): """ Parse OpenSSL-style foo.0, foo.1, ... subscripted options. - Returns a list of values matching the specified option name. + Returns iteration of values matching the specified option name. """ matches = [] if section is None: section = self.default_section if self.cfg.has_option(section, option): - matches.append((-1, self.get(option, section = section))) - for key in self.cfg.options(section): - s = key.rsplit(".", 1) - if len(s) == 2 and s[0] == option and s[1].isdigit(): - matches.append((int(s[1]), self.get(option, section = section))) + yield self.cfg.get(section, option) + option += "." + matches = [o for o in self.cfg.options(section) if o.startswith(option) and o[len(option):].isdigit()] matches.sort() - return [match[1] for match in matches] + for option in matches: + yield self.cfg.get(section, option) _regexp = re.compile("\\${(.*?)::(.*?)}") @@ -203,10 +202,12 @@ class parser(object): import rpki.log import rpki.daemonize - try: - rpki.http.debug_http = self.getboolean("debug_http") - except ConfigParser.NoOptionError: - pass + for line in self.multiget("configure_logger"): + try: + name, level = line.split() + logging.getLogger(name).setLevel(getattr(logging, level.upper())) + except Exception, e: + logger.warning("Could not process configure_logger line %r: %s", line, e) try: rpki.http.want_persistent_client = self.getboolean("want_persistent_client") diff --git a/rpki/http.py b/rpki/http.py index ed9be5f4..546dd310 100644 --- a/rpki/http.py +++ b/rpki/http.py @@ -42,10 +42,6 @@ logger = logging.getLogger(__name__) # HTTP content type used for all RPKI messages. rpki_content_type = "application/x-rpki" -## @var debug_http -# Verbose chatter about HTTP streams. -debug_http = False - ## @var want_persistent_client # Whether we want persistent HTTP client streams, when server also supports them. want_persistent_client = False @@ -295,11 +291,15 @@ def addr_to_string(addr): return "%s.%d" % (addr[0], addr[1]) raise TypeError +@rpki.log.class_logger(logger) class http_stream(asynchat.async_chat): """ Virtual class representing an HTTP message stream. """ + # Keep pylint happy; @class_logger overwrites this. + logger = None + def __repr__(self): status = ["connected"] if self.connected else [] try: @@ -309,7 +309,7 @@ class http_stream(asynchat.async_chat): return rpki.log.log_repr(self, *status) def __init__(self, sock = None): - self.logger = logging.LoggerAdapter(logger, dict(context = self)) + self.logger = logging.LoggerAdapter(self.logger, dict(context = self)) asynchat.async_chat.__init__(self, sock) self.buffer = [] self.timer = rpki.async.timer(self.handle_timeout) @@ -471,6 +471,7 @@ class http_stream(asynchat.async_chat): self.timer.cancel() asynchat.async_chat.handle_close(self) +@rpki.log.class_logger(logger) class http_server(http_stream): """ HTTP server stream. @@ -570,6 +571,7 @@ class http_server(http_stream): self.logger.debug("Listening for next message") self.restart() +@rpki.log.class_logger(logger) class http_listener(asyncore.dispatcher): """ Listener for incoming HTTP connections. @@ -583,7 +585,7 @@ class http_listener(asyncore.dispatcher): return rpki.log.log_repr(self, *status) def __init__(self, handlers, addrinfo): - self.logger = logging.LoggerAdapter(logger, dict(context = self)) + self.logger = logging.LoggerAdapter(self.logger, dict(context = self)) asyncore.dispatcher.__init__(self) self.handlers = handlers try: @@ -629,6 +631,7 @@ class http_listener(asyncore.dispatcher): raise self.logger.exception("Error in HTTP listener") +@rpki.log.class_logger(logger) class http_client(http_stream): """ HTTP client stream. @@ -815,6 +818,7 @@ class http_client(http_stream): http_stream.handle_error(self) self.queue.return_result(self, edata, detach = True) +@rpki.log.class_logger(logger) class http_queue(object): """ Queue of pending HTTP requests for a single destination. This class @@ -826,7 +830,7 @@ class http_queue(object): return rpki.log.log_repr(self, addr_to_string(self.hostport)) def __init__(self, hostport): - self.logger = logging.LoggerAdapter(logger, dict(context = self)) + self.logger = logging.LoggerAdapter(self.logger, dict(context = self)) self.hostport = hostport self.client = None self.logger.debug("Created") @@ -948,8 +952,7 @@ def client(msg, url, callback, errback): u.fragment != ""): raise rpki.exceptions.BadClientURL("Unusable URL %s" % url) - if debug_http: - logger.debug("Contacting %s", url) + logger.debug("Contacting %s", url) request = http_request( cmd = "POST", @@ -962,8 +965,7 @@ def client(msg, url, callback, errback): hostport = (u.hostname or "localhost", u.port or default_tcp_port) - if debug_http: - logger.debug("Created request %r for %s", request, addr_to_string(hostport)) + logger.debug("Created request %r for %s", request, addr_to_string(hostport)) if hostport not in client_queues: client_queues[hostport] = http_queue(hostport) client_queues[hostport].request(request) @@ -971,8 +973,7 @@ def client(msg, url, callback, errback): # Defer connection attempt until after we've had time to process any # pending I/O events, in case connections have closed. - if debug_http: - logger.debug("Scheduling connection startup for %r", request) + logger.debug("Scheduling connection startup for %r", request) rpki.async.event_defer(client_queues[hostport].restart) def server(handlers, port, host = ""): diff --git a/rpki/log.py b/rpki/log.py index 32ded80f..2abb3b2c 100644 --- a/rpki/log.py +++ b/rpki/log.py @@ -219,6 +219,21 @@ def init(ident = None, args = None): setproctitle.setproctitle(ident) +def class_logger(module_logger, attribute = "logger"): + """ + Class decorator to add a class-level Logger object as a class + attribute. This allows control of debugging messages at the class + level rather than just the module level. + + This decorator takes the module logger as an argument. + """ + + def decorator(cls): + setattr(cls, attribute, module_logger.getChild(cls.__name__)) + return cls + return decorator + + def log_repr(obj, *tokens): """ Constructor for __repr__() strings, handles suppression of Python |