From 717534f5a10d288081a0d8b40644794cc1b38861 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Mon, 6 Jun 2011 16:06:00 +0200 Subject: [PATCH 01/22] [trac756] Get rid of original isc.log module --- configure.ac | 2 - src/bin/xfrout/tests/xfrout_test.py.in | 6 +- src/bin/xfrout/xfrout.py.in | 81 +++---- src/lib/python/isc/__init__.py | 1 - src/lib/python/isc/log/Makefile.am | 8 - src/lib/python/isc/log/__init__.py | 1 - src/lib/python/isc/log/log.py | 280 ----------------------- src/lib/python/isc/log/tests/Makefile.am | 2 +- src/lib/python/isc/log/tests/log_test.in | 26 --- src/lib/python/isc/log/tests/log_test.py | 237 ------------------- 10 files changed, 46 insertions(+), 598 deletions(-) delete mode 100644 src/lib/python/isc/log/__init__.py delete mode 100644 src/lib/python/isc/log/log.py delete mode 100644 src/lib/python/isc/log/tests/log_test.in delete mode 100644 src/lib/python/isc/log/tests/log_test.py diff --git a/configure.ac b/configure.ac index 3d8593110b..33e0ff6d4e 100644 --- a/configure.ac +++ b/configure.ac @@ -787,7 +787,6 @@ AC_CONFIG_FILES([Makefile src/lib/python/isc/config/Makefile src/lib/python/isc/config/tests/Makefile src/lib/python/isc/log/Makefile - src/lib/python/isc/log/tests/Makefile src/lib/python/isc/net/Makefile src/lib/python/isc/net/tests/Makefile src/lib/python/isc/notify/Makefile @@ -883,7 +882,6 @@ AC_OUTPUT([doc/version.ent src/lib/config/tests/data_def_unittests_config.h src/lib/python/isc/config/tests/config_test src/lib/python/isc/cc/tests/cc_test - src/lib/python/isc/log/tests/log_test src/lib/python/isc/notify/tests/notify_out_test src/lib/dns/gen-rdatacode.py src/lib/python/bind10_config.py diff --git a/src/bin/xfrout/tests/xfrout_test.py.in b/src/bin/xfrout/tests/xfrout_test.py.in index c0db5c6bcc..adabf48ebf 100644 --- a/src/bin/xfrout/tests/xfrout_test.py.in +++ b/src/bin/xfrout/tests/xfrout_test.py.in @@ -116,8 +116,8 @@ class TestXfroutSession(unittest.TestCase): def setUp(self): self.sock = MySocket(socket.AF_INET,socket.SOCK_STREAM) - self.log = isc.log.NSLogger('xfrout', '', severity = 'critical', log_to_console = False ) - self.xfrsess = MyXfroutSession(self.sock, None, Dbserver(), self.log, TSIGKeyRing()) + #self.log = isc.log.NSLogger('xfrout', '', severity = 'critical', log_to_console = False ) + self.xfrsess = MyXfroutSession(self.sock, None, Dbserver(), TSIGKeyRing()) self.mdata = bytes(b'\xd6=\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07example\x03com\x00\x00\xfc\x00\x01') self.soa_record = (4, 3, 'example.com.', 'com.example.', 3600, 'SOA', None, 'master.example.com. admin.example.com. 1234 3600 1800 2419200 7200') @@ -520,7 +520,7 @@ class MyUnixSockServer(UnixSockServer): self._shutdown_event = threading.Event() self._max_transfers_out = 10 self._cc = MyCCSession() - self._log = isc.log.NSLogger('xfrout', '', severity = 'critical', log_to_console = False ) + #self._log = isc.log.NSLogger('xfrout', '', severity = 'critical', log_to_console = False ) class TestUnixSockServer(unittest.TestCase): def setUp(self): diff --git a/src/bin/xfrout/xfrout.py.in b/src/bin/xfrout/xfrout.py.in index f352c747b0..40bad8565d 100755 --- a/src/bin/xfrout/xfrout.py.in +++ b/src/bin/xfrout/xfrout.py.in @@ -26,7 +26,7 @@ from isc.datasrc import sqlite3_ds from socketserver import * import os from isc.config.ccsession import * -from isc.log.log import * +#from isc.log.log import * from isc.cc import SessionError, SessionTimeout from isc.notify import notify_out import isc.util.process @@ -88,13 +88,13 @@ def get_rrset_len(rrset): class XfroutSession(): - def __init__(self, sock_fd, request_data, server, log, tsig_key_ring): + def __init__(self, sock_fd, request_data, server, tsig_key_ring): # The initializer for the superclass may call functions # that need _log to be set, so we set it first self._sock_fd = sock_fd self._request_data = request_data self._server = server - self._log = log + #self._log = log self._tsig_key_ring = tsig_key_ring self._tsig_ctx = None self._tsig_len = 0 @@ -110,7 +110,8 @@ class XfroutSession(): self.dns_xfrout_start(self._sock_fd, self._request_data) #TODO, avoid catching all exceptions except Exception as e: - self._log.log_message("error", str(e)) + #self._log.log_message("error", str(e)) + pass os.close(self._sock_fd) @@ -137,7 +138,7 @@ class XfroutSession(): rcode = self._check_request_tsig(msg, mdata) except Exception as err: - self._log.log_message("error", str(err)) + #self._log.log_message("error", str(err)) return Rcode.FORMERR(), None return rcode, msg @@ -244,16 +245,17 @@ class XfroutSession(): zone_name = self._get_query_zone_name(msg) rcode_ = self._check_xfrout_available(zone_name) if rcode_ != Rcode.NOERROR(): - self._log.log_message("info", "transfer of '%s/IN' failed: %s", - zone_name, rcode_.to_text()) + #self._log.log_message("info", "transfer of '%s/IN' failed: %s", + # zone_name, rcode_.to_text()) return self. _reply_query_with_error_rcode(msg, sock_fd, rcode_) try: - self._log.log_message("info", "transfer of '%s/IN': AXFR started" % zone_name) + #self._log.log_message("info", "transfer of '%s/IN': AXFR started" % zone_name) self._reply_xfrout_query(msg, sock_fd, zone_name) - self._log.log_message("info", "transfer of '%s/IN': AXFR end" % zone_name) + #self._log.log_message("info", "transfer of '%s/IN': AXFR end" % zone_name) except Exception as err: - self._log.log_message("error", str(err)) + #self._log.log_message("error", str(err)) + pass self._server.decrease_transfers_counter() return @@ -317,7 +319,7 @@ class XfroutSession(): for rr_data in sqlite3_ds.get_zone_datas(zone_name, self._server.get_db_file()): if self._server._shutdown_event.is_set(): # Check if xfrout is shutdown - self._log.log_message("info", "xfrout process is being shutdown") + #self._log.log_message("info", "xfrout process is being shutdown") return # TODO: RRType.SOA() ? if RRType(rr_data[5]) == RRType("SOA"): #ignore soa record @@ -357,7 +359,7 @@ class XfroutSession(): class UnixSockServer(socketserver_mixin.NoPollMixIn, ThreadingUnixStreamServer): '''The unix domain socket server which accept xfr query sent from auth server.''' - def __init__(self, sock_file, handle_class, shutdown_event, config_data, cc, log): + def __init__(self, sock_file, handle_class, shutdown_event, config_data, cc): self._remove_unused_sock_file(sock_file) self._sock_file = sock_file socketserver_mixin.NoPollMixIn.__init__(self) @@ -366,7 +368,7 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn, ThreadingUnixStreamServer): self._transfers_counter = 0 self._shutdown_event = shutdown_event self._write_sock, self._read_sock = socket.socketpair() - self._log = log + #self._log = log self.update_config_data(config_data) self._cc = cc @@ -394,7 +396,7 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn, ThreadingUnixStreamServer): try: request, client_address = self.get_request() except socket.error: - self._log.log_message("error", "Failed to fetch request") + #self._log.log_message("error", "Failed to fetch request") return # Check self._shutdown_event to ensure the real shutdown comes. @@ -408,7 +410,7 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn, ThreadingUnixStreamServer): (rlist, wlist, xlist) = ([], [], []) continue else: - self._log.log_message("error", "Error with select(): %s" %e) + #self._log.log_message("error", "Error with select(): %s" %e) break # self.server._shutdown_event will be set by now, if it is not a false @@ -419,8 +421,8 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn, ThreadingUnixStreamServer): try: self.process_request(request) except: - self._log.log_message("error", "Exception happened during processing of %s" - % str(client_address)) + #self._log.log_message("error", "Exception happened during processing of %s" + # % str(client_address)) break def _handle_request_noblock(self): @@ -438,8 +440,8 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn, ThreadingUnixStreamServer): # This may happen when one xfrout process try to connect to # xfrout unix socket server, to check whether there is another # xfrout running. - if sock_fd == FD_COMM_ERROR: - self._log.log_message("error", "Failed to receive the file descriptor for XFR connection") + #if sock_fd == FD_COMM_ERROR: + #self._log.log_message("error", "Failed to receive the file descriptor for XFR connection") return # receive request msg @@ -456,7 +458,7 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn, ThreadingUnixStreamServer): def finish_request(self, sock_fd, request_data): '''Finish one request by instantiating RequestHandlerClass.''' - self.RequestHandlerClass(sock_fd, request_data, self, self._log, self.tsig_key_ring) + self.RequestHandlerClass(sock_fd, request_data, self, self.tsig_key_ring) def _remove_unused_sock_file(self, sock_file): '''Try to remove the socket file. If the file is being used @@ -464,8 +466,8 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn, ThreadingUnixStreamServer): If it's not a socket file or nobody is listening , it will be removed. If it can't be removed, exit from python. ''' if self._sock_file_in_use(sock_file): - self._log.log_message("error", "Fail to start xfrout process, unix socket file '%s'" - " is being used by another xfrout process\n" % sock_file) + #self._log.log_message("error", "Fail to start xfrout process, unix socket file '%s'" + # " is being used by another xfrout process\n" % sock_file) sys.exit(0) else: if not os.path.exists(sock_file): @@ -474,7 +476,7 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn, ThreadingUnixStreamServer): try: os.unlink(sock_file) except OSError as err: - self._log.log_message("error", "[b10-xfrout] Fail to remove file %s: %s\n" % (sock_file, err)) + #self._log.log_message("error", "[b10-xfrout] Fail to remove file %s: %s\n" % (sock_file, err)) sys.exit(0) def _sock_file_in_use(self, sock_file): @@ -495,17 +497,18 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn, ThreadingUnixStreamServer): try: os.unlink(self._sock_file) except Exception as e: - self._log.log_message('error', str(e)) + #self._log.log_message('error', str(e)) + pass def update_config_data(self, new_config): '''Apply the new config setting of xfrout module. ''' - self._log.log_message('info', 'update config data start.') + #self._log.log_message('info', 'update config data start.') self._lock.acquire() self._max_transfers_out = new_config.get('transfers_out') self.set_tsig_key_ring(new_config.get('tsig_key_ring')) - self._log.log_message('info', 'max transfer out : %d', self._max_transfers_out) + #self._log.log_message('info', 'max transfer out : %d', self._max_transfers_out) self._lock.release() - self._log.log_message('info', 'update config data complete.') + #self._log.log_message('info', 'update config data complete.') def set_tsig_key_ring(self, key_list): """Set the tsig_key_ring , given a TSIG key string list representation. """ @@ -521,7 +524,7 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn, ThreadingUnixStreamServer): self.tsig_key_ring.add(TSIGKey(key_item)) except InvalidParameter as ipe: errmsg = "bad TSIG key string: " + str(key_item) - self._log.log_message('error', '%s' % errmsg) + #self._log.log_message('error', '%s' % errmsg) def get_db_file(self): file, is_default = self._cc.get_remote_config_value("Auth", "database_file") @@ -553,16 +556,16 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn, ThreadingUnixStreamServer): class XfroutServer: def __init__(self): self._unix_socket_server = None - self._log = None + #self._log = None self._listen_sock_file = UNIX_SOCKET_FILE self._shutdown_event = threading.Event() self._cc = isc.config.ModuleCCSession(SPECFILE_LOCATION, self.config_handler, self.command_handler) self._config_data = self._cc.get_full_config() self._cc.start() self._cc.add_remote_config(AUTH_SPECFILE_LOCATION); - self._log = isc.log.NSLogger(self._config_data.get('log_name'), self._config_data.get('log_file'), - self._config_data.get('log_severity'), self._config_data.get('log_versions'), - self._config_data.get('log_max_bytes'), True) + #self._log = isc.log.NSLogger(self._config_data.get('log_name'), self._config_data.get('log_file'), + # self._config_data.get('log_severity'), self._config_data.get('log_versions'), + # self._config_data.get('log_max_bytes'), True) self._start_xfr_query_listener() self._start_notifier() @@ -570,13 +573,13 @@ class XfroutServer: '''Start a new thread to accept xfr query. ''' self._unix_socket_server = UnixSockServer(self._listen_sock_file, XfroutSession, self._shutdown_event, self._config_data, - self._cc, self._log); + self._cc) listener = threading.Thread(target=self._unix_socket_server.serve_forever) listener.start() def _start_notifier(self): datasrc = self._unix_socket_server.get_db_file() - self._notifier = notify_out.NotifyOut(datasrc, self._log) + self._notifier = notify_out.NotifyOut(datasrc) self._notifier.dispatcher() def send_notify(self, zone_name, zone_class): @@ -591,8 +594,8 @@ class XfroutServer: continue self._config_data[key] = new_config[key] - if self._log: - self._log.update_config(new_config) + #if self._log: + # self._log.update_config(new_config) if self._unix_socket_server: self._unix_socket_server.update_config_data(self._config_data) @@ -621,7 +624,7 @@ class XfroutServer: def command_handler(self, cmd, args): if cmd == "shutdown": - self._log.log_message("info", "Received shutdown command.") + #self._log.log_message("info", "Received shutdown command.") self.shutdown() answer = create_answer(0) @@ -629,8 +632,8 @@ class XfroutServer: zone_name = args.get('zone_name') zone_class = args.get('zone_class') if zone_name and zone_class: - self._log.log_message("info", "zone '%s/%s': receive notify others command" \ - % (zone_name, zone_class)) + #self._log.log_message("info", "zone '%s/%s': receive notify others command" \ + # % (zone_name, zone_class)) self.send_notify(zone_name, zone_class) answer = create_answer(0) else: diff --git a/src/lib/python/isc/__init__.py b/src/lib/python/isc/__init__.py index 9204792236..8fcbf4256d 100644 --- a/src/lib/python/isc/__init__.py +++ b/src/lib/python/isc/__init__.py @@ -2,4 +2,3 @@ import isc.datasrc import isc.cc import isc.config #import isc.dns -import isc.log diff --git a/src/lib/python/isc/log/Makefile.am b/src/lib/python/isc/log/Makefile.am index acd2acc0f3..e69de29bb2 100644 --- a/src/lib/python/isc/log/Makefile.am +++ b/src/lib/python/isc/log/Makefile.am @@ -1,8 +0,0 @@ -SUBDIRS = . tests - -python_PYTHON = __init__.py log.py - -pythondir = $(pyexecdir)/isc/log - -pytest: - $(SHELL) tests/log_test diff --git a/src/lib/python/isc/log/__init__.py b/src/lib/python/isc/log/__init__.py deleted file mode 100644 index a34e164d3f..0000000000 --- a/src/lib/python/isc/log/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from isc.log.log import * diff --git a/src/lib/python/isc/log/log.py b/src/lib/python/isc/log/log.py deleted file mode 100644 index 74261e2960..0000000000 --- a/src/lib/python/isc/log/log.py +++ /dev/null @@ -1,280 +0,0 @@ -# Copyright (C) 2010 Internet Systems Consortium. -# -# 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 INTERNET SYSTEMS CONSORTIUM -# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL -# INTERNET SYSTEMS CONSORTIUM 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 module is to convert python logging module over -to log4python. -Copyright (C) 2010 Internet Systems Consortium. -To use, simply 'import isc.log.log' and log away! -""" -import os -import sys -import syslog -import logging -import logging.handlers - -"""LEVELS: logging levels mapping -""" -LEVELS = {'debug' : logging.DEBUG, - 'info' : logging.INFO, - 'warning' : logging.WARNING, - 'error' : logging.ERROR, - 'critical' : logging.CRITICAL} - -FORMATTER = logging.Formatter("%(name)s: %(levelname)s: %(message)s") -TIME_FORMATTER = logging.Formatter("%(asctime)s.%(msecs)03d %(name)s: %(levelname)s: %(message)s", - "%d-%b-%Y %H:%M:%S") - -def log_err(err_type, err_msg): - sys.stderr.write(err_type + ": " + "%s.\n" % str(err_msg)[str(err_msg).find(']')+1:]) - - -class NSFileLogHandler(logging.handlers.RotatingFileHandler): - """RotatingFileHandler: replace RotatingFileHandler with a custom handler""" - - def __init__(self, filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=0): - abs_file_name = self._get_abs_file_path(filename) - """Create log directory beforehand, because the underlying logging framework won't - create non-exsiting log directory on writing logs. - """ - if not (os.path.exists(os.path.dirname(abs_file_name))): - os.makedirs(os.path.dirname(abs_file_name)) - super(NSFileLogHandler, self).__init__(abs_file_name, mode, maxBytes, - backupCount, encoding, delay) - - def handleError(self, record): - """Overwrite handleError to provide more user-friendly error messages""" - if logging.raiseExceptions: - ei = sys.exc_info() - if (ei[1]): - sys.stderr.write("[b10-logging] : " + str(ei[1])) - - def _get_abs_file_path(self, file_name): - """ Get absolute file path""" - # For a bare filename, log_dir will be set the current directory. - if not os.path.dirname(file_name): - abs_file_dir = os.getcwd() - else: - abs_file_dir = os.path.abspath(os.path.dirname(file_name)) - abs_file_name = os.path.join(abs_file_dir, os.path.basename(file_name)) - return abs_file_name - - def shouldRollover(self, record): - """Rewrite RotatingFileHandler.shouldRollover. - - If the log file is deleted at runtime, a new file will be created. - """ - dfn = self.baseFilename - if (self.stream) and (not os.path.exists(dfn)): #Does log file exist? - self.stream = None - """ Log directory may be deleted while bind10 running or updated with a - non-existing directory. Need to create log directory beforehand, because - the underlying logging framework won't create non-exsiting log directory - on writing logs. - """ - if not (os.path.exists(os.path.dirname(dfn))): #Does log subdirectory exist? - os.makedirs(os.path.dirname(dfn)) - self.stream = self._open() - return super(NSFileLogHandler, self).shouldRollover(record) - - def update_config(self, file_name, backup_count, max_bytes): - """Update RotatingFileHandler configuration. - Changes will be picked up in the next call to shouldRollover(). - - input: - log file name - max backup count - predetermined log file size - """ - abs_file_name = self._get_abs_file_path(file_name) - self.baseFilename = abs_file_name - self.maxBytes = max_bytes - self.backupCount = backup_count - - -class NSSysLogHandler(logging.Handler): - """Replace SysLogHandler with a custom handler - - A handler class which sends formatted logging records to a syslog - server. - """ - def __init__(self, ident, logopt=0, facility=syslog.LOG_USER): - """Initialize a handler. - - If facility is not specified, LOG_USER is used. - """ - super(NSSysLogHandler, self).__init__() - self._ident = ident - self._logopt = logopt - self._facility = facility - self._mappings = { - logging.DEBUG: syslog.LOG_DEBUG, - logging.INFO: syslog.LOG_INFO, - logging.WARNING: syslog.LOG_WARNING, - logging.ERROR: syslog.LOG_ERR, - logging.CRITICAL: syslog.LOG_CRIT, - } - - def _encodeLevel(self, level): - """Encoding the priority.""" - return self._mappings.get(level, syslog.LOG_INFO) - - def emit(self, record): - """Emit a record. - - The record is formatted, and then sent to the syslog server. If - exception information is present, it is NOT sent to the server. - """ - syslog.openlog(self._ident, self._logopt, self._facility) - msg = self.format(record) - prio = self._encodeLevel(record.levelno) - syslog.syslog(prio, msg) - syslog.closelog() - - -class NSLogger(logging.getLoggerClass()): - """Override logging.logger behaviour.""" - def __init__(self, log_name, log_file, severity='debug', versions=0, - max_bytes=0, log_to_console=True): - """Initializes the logger with some specific parameters - - If log_to_console is True, stream handler will be used; - else syslog handler will be used. - - To disable file handler, set log_file = ''. - """ - self._log_name = log_name - self._log_file = log_file - self._severity = severity - self._versions = versions - self._max_bytes = max_bytes - - super(NSLogger, self).__init__(self._log_name) - - # Set up a specific logger with our desired output level - logLevel = LEVELS.get(self._severity, logging.NOTSET) - self.setLevel(logLevel) - - self._file_handler = None - self._stream_handler = None - self._syslog_handler = None - - self._add_rotate_handler(self._log_file, self._versions, self._max_bytes) - if log_to_console: - self._add_stream_handler() - else: - self._add_syslog_handler() - - def _add_rotate_handler(self, log_file, backup_count, max_bytes): - """Add a rotate file handler. - - input: - log_file : the location of log file. Handler will not be created - if log_file='' - max_bytes : limit log growth - backup_count : max backup count - """ - if (log_file != 0 and log_file != ''): - try: - self._file_handler = NSFileLogHandler(filename = log_file, - maxBytes = max_bytes, backupCount = backup_count) - except (IOError, OSError) as e: - self._file_handler = None - log_err("[b10-logging] Add file handler fail", str(e)) - return - self._file_handler.setFormatter(TIME_FORMATTER) - self.addHandler(self._file_handler) - - def _add_stream_handler(self): - """Add a stream handler. - - sys.stderr will be used for logging output. - """ - self._stream_handler = logging.StreamHandler() - self._stream_handler.setFormatter(TIME_FORMATTER) - self.addHandler(self._stream_handler) - - def _add_syslog_handler(self, nsfacility=syslog.LOG_USER): - """Add a syslog handler. - - If facility is not specified, LOG_USER is used. - The default severity level is INFO. - """ - self._syslog_handler = NSSysLogHandler('BIND10', facility = nsfacility) - self._syslog_handler.setFormatter(FORMATTER) - #set syslog handler severity level INFO - self._syslog_handler.setLevel(logging.INFO) - self.addHandler(self._syslog_handler) - - def _update_rotate_handler(self, log_file, backup_count, max_bytes): - """If the rotate file handler has been added to the logger, update its - configuration, or add it to the logger. - """ - if (self._file_handler in self.handlers): - if (log_file != 0 and log_file != ''): - self._file_handler.update_config(log_file, backup_count, max_bytes) - else: - """If log file is empty, the handler will be removed.""" - self._file_handler.flush() - self._file_handler.close() - self.removeHandler(self._file_handler) - else: - self._add_rotate_handler(log_file, backup_count, max_bytes) - - def _get_config(self, config_data): - """Get config data from module configuration""" - - log_file_str = config_data.get('log_file') - if (log_file_str): - self._log_file = log_file_str - - severity_str = config_data.get('log_severity') - if (severity_str): - self._severity = severity_str - - versions_str = config_data.get('log_versions') - if (versions_str): - self._versions = int(versions_str) - - max_bytes_str = config_data.get('log_max_bytes') - if (max_bytes_str): - self._max_bytes = int(max_bytes_str) - - def update_config(self, config_data): - """Update logger's configuration. - - We can update logger's log level and its rotate file handler's configuration. - """ - self._get_config(config_data) - - logLevel = LEVELS.get(self._severity, logging.NOTSET) - if (logLevel != self.getEffectiveLevel()): - self.setLevel(logLevel) - self._update_rotate_handler(self._log_file, self._versions, self._max_bytes) - - def log_message(self, level, msg, *args, **kwargs): - """Log 'msg % args' with the integer severity 'level'. - - To pass exception information, use the keyword argument exc_info with - a true value, e.g. - - logger.log_message('info', "We have a %s", "mysterious problem"). - """ - logLevel = LEVELS.get(level, logging.NOTSET) - try: - self.log(logLevel, msg, *args, **kwargs) - except (TypeError, KeyError) as e: - sys.stderr.write("[b10-logging] Log message fail %s\n" % (str(e))) - - diff --git a/src/lib/python/isc/log/tests/Makefile.am b/src/lib/python/isc/log/tests/Makefile.am index 86b3e5d0a1..50eacd9402 100644 --- a/src/lib/python/isc/log/tests/Makefile.am +++ b/src/lib/python/isc/log/tests/Makefile.am @@ -1,5 +1,5 @@ PYCOVERAGE_RUN = @PYCOVERAGE_RUN@ -PYTESTS = log_test.py +PYTESTS = EXTRA_DIST = $(PYTESTS) # test using command-line arguments, so use check-local target instead of TESTS diff --git a/src/lib/python/isc/log/tests/log_test.in b/src/lib/python/isc/log/tests/log_test.in deleted file mode 100644 index 60e5e3f699..0000000000 --- a/src/lib/python/isc/log/tests/log_test.in +++ /dev/null @@ -1,26 +0,0 @@ -#! /bin/sh - -# Copyright (C) 2010 Internet Systems Consortium. -# -# 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 INTERNET SYSTEMS CONSORTIUM -# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL -# INTERNET SYSTEMS CONSORTIUM 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. - -PYTHON_EXEC=${PYTHON_EXEC:-@PYTHON@} -export PYTHON_EXEC - -TEST_PATH=@abs_top_srcdir@/src/lib/python/isc/log/tests -PYTHONPATH=@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/python -export PYTHONPATH - -cd ${TEST_PATH} -exec ${PYTHON_EXEC} -O log_test.py $* diff --git a/src/lib/python/isc/log/tests/log_test.py b/src/lib/python/isc/log/tests/log_test.py deleted file mode 100644 index 026dee1e45..0000000000 --- a/src/lib/python/isc/log/tests/log_test.py +++ /dev/null @@ -1,237 +0,0 @@ -# Copyright (C) 2010 Internet Systems Consortium. -# -# 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 INTERNET SYSTEMS CONSORTIUM -# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL -# INTERNET SYSTEMS CONSORTIUM 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. - -# -# Tests for the python logging module -# - -from isc.log.log import * -import unittest -import os -import sys -import tempfile - - -class TestRotateFileHandler(unittest.TestCase): - - def setUp(self): - self.FILE_LOG1 = tempfile.NamedTemporaryFile(mode='w', - prefix="b10", - delete=True) - self.FILE_LOG2 = tempfile.NamedTemporaryFile(mode='w', - prefix="b10", - delete=True) - self.FILE_LOG3 = tempfile.NamedTemporaryFile(mode='w', - prefix="b10", - delete=True) - self.handler = NSFileLogHandler(filename = self.FILE_LOG1.name, - maxBytes = 1024, - backupCount = 5) - - def test_shouldRollover(self): - if(os.path.exists(self.FILE_LOG1.name)): - os.remove(self.FILE_LOG1.name) - record = logging.LogRecord(None, None, "", 0, "rotate file handler", (), None, None) - self.handler.shouldRollover(record) - self.assertTrue(os.path.exists(self.FILE_LOG1.name)) - - def test_get_absolute_file_path(self): - abs_file_name = self.handler._get_abs_file_path(self.FILE_LOG1.name) - self.assertEqual(abs_file_name, self.FILE_LOG1.name) - # test bare filename - file_name1 = "bind10.py" - abs_file_name = self.handler._get_abs_file_path(file_name1) - self.assertEqual(abs_file_name, os.path.join(os.getcwd(), file_name1)) - # test relative path - file_name2 = "./bind10.py" - abs_file_name = self.handler._get_abs_file_path(file_name2) - self.assertEqual(abs_file_name, os.path.join(os.getcwd(), os.path.basename(file_name2))) - - def test_update_config(self): - self.handler.update_config(self.FILE_LOG2.name, 3, 512) - self.assertEqual(self.handler.baseFilename, self.FILE_LOG2.name) - self.assertEqual(self.handler.maxBytes, 512) - self.assertEqual(self.handler.backupCount, 3) - - # check the existence of new log file. - # emit() will call shouldRollover() to update the log file - if(os.path.exists(self.FILE_LOG2.name)): - os.remove(self.FILE_LOG2.name) - record = logging.LogRecord(None, None, "", 0, "rotate file handler", (), None, None) - self.handler.emit(record) - self.assertTrue(os.path.exists(self.FILE_LOG2.name)) - - def test_handle_Error(self): - if(os.path.exists(self.FILE_LOG3.name)): - os.remove(self.FILE_LOG3.name) - # redirect error message to file - savederr = sys.stderr - errfd = open(self.FILE_LOG3.name, 'w+') - sys.stderr = errfd - record = logging.LogRecord(None, None, "", 0, "record message", (), None, None) - try: - raise ValueError("ValueError") - except ValueError: - self.handler.handleError(record) - - self.assertEqual("[b10-logging] : ValueError", errfd.read()) - sys.stderr = savederr - errfd.close() - - def tearDown(self): - self.handler.flush() - self.handler.close() - self.FILE_LOG1.close() - self.FILE_LOG2.close() - self.FILE_LOG3.close() - -class TestSysLogHandler(unittest.TestCase): - def setUp(self): - self.handler = NSSysLogHandler("BIND10") - - def test_encodeLevel(self): - sysLevel = self.handler._encodeLevel(logging.ERROR) - self.assertEqual(sysLevel, syslog.LOG_ERR) - - def test_emit(self): - syslog_message = "bind10 syslog testing" - record = logging.LogRecord(None, None, "", 0, syslog_message, (), None, None) - self.handler.emit(record) - -class TestLogging(unittest.TestCase): - - def setUp(self): - self.FILE_STREAM_LOG1 = tempfile.NamedTemporaryFile(mode='w', - prefix="b10", - delete=True) - self.FILE_STREAM_LOG2 = tempfile.NamedTemporaryFile(mode='w', - prefix="b10", - delete=True) - self.FILE_STREAM_LOG3 = tempfile.NamedTemporaryFile(mode='w', - prefix="b10", - delete=True) - self.file_stream_logger = NSLogger('File_Stream_Logger', - self.FILE_STREAM_LOG1.name, - 'debug', 5, 1024, True) - self.syslog_logger = NSLogger('SysLogger', '', 'info', 5, 1024, False) - self.stderr_bak = sys.stderr - sys.stderr = open(os.devnull, 'w') - - def test_logging_init(self): - self.assertNotEqual(self.file_stream_logger._file_handler, None) - self.assertNotEqual(self.file_stream_logger._stream_handler, None) - self.assertEqual(self.file_stream_logger._syslog_handler, None) - - self.assertIn(self.file_stream_logger._file_handler, self.file_stream_logger.handlers) - self.assertIn(self.file_stream_logger._stream_handler, self.file_stream_logger.handlers) - self.assertNotIn(self.file_stream_logger._syslog_handler, self.file_stream_logger.handlers) - logLevel = LEVELS.get('debug', logging.NOTSET) - self.assertEqual(self.file_stream_logger.getEffectiveLevel(), logLevel) - - self.assertEqual(self.syslog_logger._file_handler, None) - self.assertEqual(self.syslog_logger._stream_handler, None) - self.assertNotEqual(self.syslog_logger._syslog_handler, None) - self.assertNotIn(self.syslog_logger._file_handler, self.syslog_logger.handlers) - self.assertNotIn(self.syslog_logger._stream_handler, self.syslog_logger.handlers) - self.assertIn(self.syslog_logger._syslog_handler, self.syslog_logger.handlers) - - logLevel = LEVELS.get('info', logging.NOTSET) - self.assertEqual(self.syslog_logger.getEffectiveLevel(), logLevel) - - def test_add_rotate_handler(self): - if(self.syslog_logger._file_handler in self.syslog_logger.handlers): - self.syslog_logger.removeHandler(self.syslog_logger._file_handler) - - self.syslog_logger._add_rotate_handler('', 5, 1024) - self.assertNotIn(self.syslog_logger._file_handler, self.syslog_logger.handlers) - - self.syslog_logger._add_rotate_handler(self.FILE_STREAM_LOG1.name, 5, 1024) - self.assertIn(self.syslog_logger._file_handler, self.syslog_logger.handlers) - - # test IOError exception - self.syslog_logger.removeHandler(self.syslog_logger._file_handler) - log_file = self.FILE_STREAM_LOG1.name + '/logfile' - self.syslog_logger._add_rotate_handler(log_file, 5, 1024) - self.assertNotIn(self.syslog_logger._file_handler, self.syslog_logger.handlers) - - def test_add_stream_handler(self): - if(self.file_stream_logger._stream_handler in self.file_stream_logger.handlers): - self.file_stream_logger.removeHandler(self.file_stream_logger._stream_handler) - - self.file_stream_logger._add_stream_handler() - self.assertIn(self.file_stream_logger._stream_handler, self.file_stream_logger.handlers) - - def test_add_syslog_handler(self): - if(self.syslog_logger._syslog_handler in self.syslog_logger.handlers): - self.syslog_logger.removeHandler(self.syslog_logger._syslog_handler) - - self.syslog_logger._add_syslog_handler() - self.assertIn(self.syslog_logger._syslog_handler, self.syslog_logger.handlers) - - def test_update_rotate_handler(self): - self.file_stream_logger._update_rotate_handler(self.FILE_STREAM_LOG2.name, 4, 1024) - self.assertIn(self.file_stream_logger._file_handler, self.file_stream_logger.handlers) - - self.file_stream_logger._update_rotate_handler('', 5, 1024) - self.assertNotIn(self.file_stream_logger._file_handler, self.file_stream_logger.handlers) - - self.file_stream_logger._update_rotate_handler(self.FILE_STREAM_LOG1.name, 4, 1024) - self.assertIn(self.file_stream_logger._file_handler, self.file_stream_logger.handlers) - - def test_get_config(self): - config_data = {'log_file' : self.FILE_STREAM_LOG1.name, - 'log_severity' : 'critical', - 'log_versions' : 4, - 'log_max_bytes' : 1024} - self.file_stream_logger._get_config(config_data) - self.assertEqual(self.file_stream_logger._log_file, self.FILE_STREAM_LOG1.name) - self.assertEqual(self.file_stream_logger._severity, 'critical') - self.assertEqual(self.file_stream_logger._versions, 4) - self.assertEqual(self.file_stream_logger._max_bytes, 1024) - - - def test_update_config(self): - update_config = {'log_file' : self.FILE_STREAM_LOG1.name, - 'log_severity' : 'error', - 'log_versions' : 4, - 'log_max_bytes' : 1024} - self.file_stream_logger.update_config(update_config) - logLevel = LEVELS.get('error', logging.NOTSET) - self.assertEqual(self.file_stream_logger.getEffectiveLevel(), logLevel) - - def test_log_message(self): - update_config = {'log_file' : self.FILE_STREAM_LOG3.name, - 'log_severity' : 'critical', - 'log_versions' : 4, - 'log_max_bytes' : 1024} - self.file_stream_logger.update_config(update_config) - self.file_stream_logger.log_message('debug', 'debug message') - self.file_stream_logger.log_message('warning', 'warning message') - self.file_stream_logger.log_message('error', 'error message') - #test non-exist log level - self.assertRaises(None, self.file_stream_logger.log_message('not-exist', 'not exist message')) - #test log_message KeyError exception - self.assertRaises(None, self.file_stream_logger.log_message('critical', 'critical message', extra=['message', 'asctime'])) - self.assertTrue(os.path.exists(self.FILE_STREAM_LOG3.name)) - - def tearDown(self): - self.FILE_STREAM_LOG1.close() - self.FILE_STREAM_LOG2.close() - self.FILE_STREAM_LOG3.close() - sys.stderr.flush(); - sys.stderr = self.stderr_bak - -if __name__ == '__main__': - unittest.main() From a215fa328b934f3d140e433725b2d7a540b826f5 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Mon, 6 Jun 2011 17:09:22 +0200 Subject: [PATCH 02/22] [trac756] Create the module It's still empty now, but it at last installs into the correct directory and loads. --- configure.ac | 1 + src/lib/python/isc/log/Makefile.am | 15 ++++++++++ src/lib/python/isc/log/main.cc | 47 ++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 src/lib/python/isc/log/main.cc diff --git a/configure.ac b/configure.ac index 33e0ff6d4e..e15d32c2dd 100644 --- a/configure.ac +++ b/configure.ac @@ -787,6 +787,7 @@ AC_CONFIG_FILES([Makefile src/lib/python/isc/config/Makefile src/lib/python/isc/config/tests/Makefile src/lib/python/isc/log/Makefile + src/lib/python/isc/log/tests/Makefile src/lib/python/isc/net/Makefile src/lib/python/isc/net/tests/Makefile src/lib/python/isc/notify/Makefile diff --git a/src/lib/python/isc/log/Makefile.am b/src/lib/python/isc/log/Makefile.am index e69de29bb2..9fac4552ff 100644 --- a/src/lib/python/isc/log/Makefile.am +++ b/src/lib/python/isc/log/Makefile.am @@ -0,0 +1,15 @@ +SUBDIRS = tests + +AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib +AM_CPPFLAGS += $(BOOST_INCLUDES) +AM_CXXFLAGS = $(B10_CXXFLAGS) + +pythondir = $(pyexecdir)/isc +python_LTLIBRARIES = log.la +log_la_SOURCES = main.cc + +log_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES) +log_la_LDFLAGS = $(PYTHON_LDFLAGS) +log_la_LDFLAGS += -module +log_la_LIBADD = $(top_builddir)/src/lib/log/liblog.la +log_la_LIBADD += $(PYTHON_LIB) diff --git a/src/lib/python/isc/log/main.cc b/src/lib/python/isc/log/main.cc new file mode 100644 index 0000000000..7ff2c1a224 --- /dev/null +++ b/src/lib/python/isc/log/main.cc @@ -0,0 +1,47 @@ +// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC 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. + +#define PY_SSIZE_T_CLEAN +#include +#include + +#include + +namespace { + +PyModuleDef iscLog = { + { PyObject_HEAD_INIT(NULL) NULL, 0, NULL}, + "log", + "Python bindings for the classes in the isc::log namespace.\n\n" + "These bindings are close match to the C++ API, but they are not complete " + "(some parts are not needed) and some are done in more python-like ways.", + -1, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +} + +PyMODINIT_FUNC +PyInit_log(void) { + PyObject* mod = PyModule_Create(&iscLog); + if (mod == NULL) { + return (NULL); + } + + return (mod); +} From 70d184ad5dac430b1591166893689ecb5b774777 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Mon, 6 Jun 2011 17:43:28 +0200 Subject: [PATCH 03/22] [trac756] Test the module can be loaded With a nasty trick to be located during tests. --- src/lib/python/isc/log/Makefile.am | 3 +++ src/lib/python/isc/log/__init__.py | 29 ++++++++++++++++++++++++ src/lib/python/isc/log/tests/Makefile.am | 4 ++-- src/lib/python/isc/log/tests/log_test.py | 18 +++++++++++++++ 4 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 src/lib/python/isc/log/__init__.py create mode 100644 src/lib/python/isc/log/tests/log_test.py diff --git a/src/lib/python/isc/log/Makefile.am b/src/lib/python/isc/log/Makefile.am index 9fac4552ff..7cdfa20fe6 100644 --- a/src/lib/python/isc/log/Makefile.am +++ b/src/lib/python/isc/log/Makefile.am @@ -13,3 +13,6 @@ log_la_LDFLAGS = $(PYTHON_LDFLAGS) log_la_LDFLAGS += -module log_la_LIBADD = $(top_builddir)/src/lib/log/liblog.la log_la_LIBADD += $(PYTHON_LIB) + +# This is not installed, it helps locate the module during tests +EXTRA_DIST = __init__.py diff --git a/src/lib/python/isc/log/__init__.py b/src/lib/python/isc/log/__init__.py new file mode 100644 index 0000000000..ad77dff1f6 --- /dev/null +++ b/src/lib/python/isc/log/__init__.py @@ -0,0 +1,29 @@ +# Copyright (C) 2011 Internet Systems Consortium. +# +# 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 INTERNET SYSTEMS CONSORTIUM +# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL +# INTERNET SYSTEMS CONSORTIUM 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 is not installed. The log.so is installed into the right place. +# It is only to find it in the .libs directory when we run as a test or +# from the build directory. +# But as nobody gives us the builddir explicitly (and we can't use generation +# from .in file, as it would put us into the builddir and we wouldn't be found) +# we guess from current directory. Any idea for something better? This should +# be enough for the tests, but would it work for B10_FROM_SOURCE as well? +# Should we look there? Or define something in bind10_config? + +import os +cwd = os.getcwd() +pos = cwd.rfind('/src/') +import sys; sys.path.insert(0, cwd[:pos] + '/src/lib/python/isc/log/.libs') +from log import * diff --git a/src/lib/python/isc/log/tests/Makefile.am b/src/lib/python/isc/log/tests/Makefile.am index 50eacd9402..fc00d0d90a 100644 --- a/src/lib/python/isc/log/tests/Makefile.am +++ b/src/lib/python/isc/log/tests/Makefile.am @@ -1,11 +1,11 @@ PYCOVERAGE_RUN = @PYCOVERAGE_RUN@ -PYTESTS = +PYTESTS = log_test.py EXTRA_DIST = $(PYTESTS) # test using command-line arguments, so use check-local target instead of TESTS check-local: if ENABLE_PYTHON_COVERAGE - touch $(abs_top_srcdir)/.coverage + touch $(abs_top_srcdir)/.coverage rm -f .coverage ${LN_S} $(abs_top_srcdir)/.coverage .coverage endif diff --git a/src/lib/python/isc/log/tests/log_test.py b/src/lib/python/isc/log/tests/log_test.py new file mode 100644 index 0000000000..d8bac272bc --- /dev/null +++ b/src/lib/python/isc/log/tests/log_test.py @@ -0,0 +1,18 @@ +# Copyright (C) 2011 Internet Systems Consortium. +# +# 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 INTERNET SYSTEMS CONSORTIUM +# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL +# INTERNET SYSTEMS CONSORTIUM 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 tests it can be loaded, nothing more yet +import isc.log + From c9abaf3a9e3e78a875e9722649615339dfb75047 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Tue, 7 Jun 2011 12:35:30 +0200 Subject: [PATCH 04/22] [trac756] Adding messages to the dictionary --- src/lib/log/compiler/message.cc | 4 +- src/lib/python/isc/log/Makefile.am | 2 +- src/lib/python/isc/log/log.cc | 170 +++++++++++++++++++++++ src/lib/python/isc/log/main.cc | 47 ------- src/lib/python/isc/log/tests/log_test.py | 17 +++ 5 files changed, 190 insertions(+), 50 deletions(-) create mode 100644 src/lib/python/isc/log/log.cc delete mode 100644 src/lib/python/isc/log/main.cc diff --git a/src/lib/log/compiler/message.cc b/src/lib/log/compiler/message.cc index 155aa55d6e..53a24eeede 100644 --- a/src/lib/log/compiler/message.cc +++ b/src/lib/log/compiler/message.cc @@ -266,12 +266,12 @@ writePythonFile(const string& file, MessageDictionary& dictionary) { "# File created from " << message_file.fullName() << " on " << currentTime() << "\n" << "\n" << - "import isc.log.message\n" << + "import isc.log\n" << "\n"; vector idents(sortedIdentifiers(dictionary)); BOOST_FOREACH(const string& ident, idents) { - pyfile << ident << " = isc.log.message.create(\"" << + pyfile << ident << " = isc.log.create_message(\"" << ident << "\", \"" << quoteString(dictionary.getText(ident)) << "\")\n"; } diff --git a/src/lib/python/isc/log/Makefile.am b/src/lib/python/isc/log/Makefile.am index 7cdfa20fe6..ede3cbf9eb 100644 --- a/src/lib/python/isc/log/Makefile.am +++ b/src/lib/python/isc/log/Makefile.am @@ -6,7 +6,7 @@ AM_CXXFLAGS = $(B10_CXXFLAGS) pythondir = $(pyexecdir)/isc python_LTLIBRARIES = log.la -log_la_SOURCES = main.cc +log_la_SOURCES = log.cc log_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES) log_la_LDFLAGS = $(PYTHON_LDFLAGS) diff --git a/src/lib/python/isc/log/log.cc b/src/lib/python/isc/log/log.cc new file mode 100644 index 0000000000..12faef06b1 --- /dev/null +++ b/src/lib/python/isc/log/log.cc @@ -0,0 +1,170 @@ +// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC 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. + +#define PY_SSIZE_T_CLEAN +#include +#include + +#include + +#include + +using namespace isc::log; + +namespace { + + +// This is for testing only. The real module will have it always set as +// NULL and will use the global dictionary. +MessageDictionary* testDictionary = NULL; + +PyObject* +setTestDictionary(PyObject*, PyObject* args) { + PyObject* enableO; + // The API doesn't seem to provide conversion to bool, + // so we do it little bit manually + if (!PyArg_ParseTuple(args, "O", &enableO)) { + return (NULL); + } + int enableI(PyObject_IsTrue(enableO)); + if (enableI == -1) { + return (NULL); + } + bool enable(enableI != 0); + + delete testDictionary; + testDictionary = NULL; + try { + if (enable) { + testDictionary = new MessageDictionary; + } + } + catch (const std::exception& e) { + PyErr_SetString(PyExc_RuntimeError, e.what()); + return (NULL); + } + catch (...) { + PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception"); + return (NULL); + } + Py_RETURN_NONE; +} + +PyObject* +createMessage(PyObject*, PyObject* args) { + const char* mid; + const char* text; + // We parse the strings + if (!PyArg_ParseTuple(args, "ss", &mid, &text)) { + return (NULL); + } + PyObject* origMid; + // And extract the original representation of the message + // ID, so we can return it instead of creating another instance. + // This call shouldn't fail if the previous suceeded. + if (!PyArg_ParseTuple(args, "Os", &origMid, &text)) { + return (NULL); + } + + try { + MessageDictionary* dict = testDictionary ? testDictionary : + &MessageDictionary::globalDictionary(); + + // We ignore the result, they will be in some kind of dupe list + // if there's a problem + dict->add(mid, text); + } + catch (const std::exception& e) { + PyErr_SetString(PyExc_RuntimeError, e.what()); + return (NULL); + } + catch (...) { + PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception"); + return (NULL); + } + + // Return the ID + Py_INCREF(origMid); + return (origMid); +} + +PyObject* +getMessage(PyObject*, PyObject* args) { + const char* mid; + if (!PyArg_ParseTuple(args, "s", &mid)) { + return (NULL); + } + + try { + MessageDictionary* dict = testDictionary ? testDictionary : + &MessageDictionary::globalDictionary(); + + const std::string& result(dict->getText(mid)); + if (result.empty()) { + Py_RETURN_NONE; + } else { + return (Py_BuildValue("s", result.c_str())); + } + } + catch (const std::exception& e) { + PyErr_SetString(PyExc_RuntimeError, e.what()); + return (NULL); + } + catch (...) { + PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception"); + return (NULL); + } +} + +PyMethodDef methods[] = { + {"set_test_dictionary", &setTestDictionary, METH_VARARGS, + "Set or unset testing mode for message dictionary. In testing, " + "the create_message and get_message functions work on different " + "than the logger-global dictionary, not polluting it."}, + {"create_message", &createMessage, METH_VARARGS, + "Creates a new message in the dictionary. You shouldn't need to " + "call this directly, it should be called by the generated message " + "file. Returns the identifier to be used in logging. The text " + "shouldn't be empty."}, + {"get_message", &getMessage, METH_VARARGS, + "Get a message. This function is for testing purposes and you don't " + "need to call it. It returns None if the message does not exist."}, + {NULL, NULL, 0, NULL} +}; + +PyModuleDef iscLog = { + { PyObject_HEAD_INIT(NULL) NULL, 0, NULL}, + "log", + "Python bindings for the classes in the isc::log namespace.\n\n" + "These bindings are close match to the C++ API, but they are not complete " + "(some parts are not needed) and some are done in more python-like ways.", + -1, + methods, + NULL, + NULL, + NULL, + NULL +}; + +} + +PyMODINIT_FUNC +PyInit_log(void) { + PyObject* mod = PyModule_Create(&iscLog); + if (mod == NULL) { + return (NULL); + } + + return (mod); +} diff --git a/src/lib/python/isc/log/main.cc b/src/lib/python/isc/log/main.cc deleted file mode 100644 index 7ff2c1a224..0000000000 --- a/src/lib/python/isc/log/main.cc +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") -// -// Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH -// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -// AND FITNESS. IN NO EVENT SHALL ISC 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. - -#define PY_SSIZE_T_CLEAN -#include -#include - -#include - -namespace { - -PyModuleDef iscLog = { - { PyObject_HEAD_INIT(NULL) NULL, 0, NULL}, - "log", - "Python bindings for the classes in the isc::log namespace.\n\n" - "These bindings are close match to the C++ API, but they are not complete " - "(some parts are not needed) and some are done in more python-like ways.", - -1, - NULL, - NULL, - NULL, - NULL, - NULL -}; - -} - -PyMODINIT_FUNC -PyInit_log(void) { - PyObject* mod = PyModule_Create(&iscLog); - if (mod == NULL) { - return (NULL); - } - - return (mod); -} diff --git a/src/lib/python/isc/log/tests/log_test.py b/src/lib/python/isc/log/tests/log_test.py index d8bac272bc..b81288ba02 100644 --- a/src/lib/python/isc/log/tests/log_test.py +++ b/src/lib/python/isc/log/tests/log_test.py @@ -15,4 +15,21 @@ # This tests it can be loaded, nothing more yet import isc.log +import unittest +class LogDict(unittest.TestCase): + def setUp(self): + # We work on a test dictionary now. + isc.log.set_test_dictionary(True) + def tearDown(self): + # Return to the global dictionary + isc.log.set_test_dictionary(False) + + def test_load_msgs(self): + # Try loading a message and see it's there, but nothing more + self.assertEqual(isc.log.create_message("ID", "Text"), "ID") + self.assertEqual(isc.log.get_message("ID"), "Text") + self.assertEqual(isc.log.get_message("no-ID"), None) + +if __name__ == '__main__': + unittest.main() From 88119987e9f33fa12243eacee75bd9ec4c99f936 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Tue, 7 Jun 2011 15:59:49 +0200 Subject: [PATCH 05/22] [trac756] Logger initialization --- src/lib/python/isc/log/log.cc | 41 ++++++++++++++++++++++++ src/lib/python/isc/log/tests/log_test.py | 21 ++++++++++++ 2 files changed, 62 insertions(+) diff --git a/src/lib/python/isc/log/log.cc b/src/lib/python/isc/log/log.cc index 12faef06b1..07a490e485 100644 --- a/src/lib/python/isc/log/log.cc +++ b/src/lib/python/isc/log/log.cc @@ -19,6 +19,7 @@ #include #include +#include using namespace isc::log; @@ -127,6 +128,38 @@ getMessage(PyObject*, PyObject* args) { } } +PyObject* +reset(PyObject*, PyObject*) { + // TODO Should we check we got exactly 0 arguments? + // But who cares, it's testing function only + LoggerManager::reset(); + Py_RETURN_NONE; +} + +PyObject* +init(PyObject*, PyObject* args) { + const char* root; + const char* file(NULL); + const char* severity("INFO"); + int dbglevel(0); + if (!PyArg_ParseTuple(args, "s|zsi", &root, &file, &severity, &dbglevel)) { + return (NULL); + } + + try { + LoggerManager::init(root, file, getSeverity(severity), dbglevel); + } + catch (const std::exception& e) { + PyErr_SetString(PyExc_RuntimeError, e.what()); + return (NULL); + } + catch (...) { + PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception"); + return (NULL); + } + Py_RETURN_NONE; +} + PyMethodDef methods[] = { {"set_test_dictionary", &setTestDictionary, METH_VARARGS, "Set or unset testing mode for message dictionary. In testing, " @@ -140,6 +173,14 @@ PyMethodDef methods[] = { {"get_message", &getMessage, METH_VARARGS, "Get a message. This function is for testing purposes and you don't " "need to call it. It returns None if the message does not exist."}, + {"reset", &reset, METH_VARARGS, + "Reset all logging. For testing purposes only, do not use."}, + {"init", &init, METH_VARARGS, + "Run-time initialization. You need to call this before you do any " + "logging, to configure the root logger name. You may also provide " + "a filename with message translations (or None if you don't want " + "any), logging severity (one of 'DEBUG', 'INFO', 'WARN', 'ERROR' or " + "'FATAL') and a debug level (integer in the range 0-99)."}, {NULL, NULL, 0, NULL} }; diff --git a/src/lib/python/isc/log/tests/log_test.py b/src/lib/python/isc/log/tests/log_test.py index b81288ba02..2f4a6b9428 100644 --- a/src/lib/python/isc/log/tests/log_test.py +++ b/src/lib/python/isc/log/tests/log_test.py @@ -31,5 +31,26 @@ class LogDict(unittest.TestCase): self.assertEqual(isc.log.get_message("ID"), "Text") self.assertEqual(isc.log.get_message("no-ID"), None) +class Manager(unittest.TestCase): + def tearDown(self): + isc.log.reset() + + def test_init_debug(self): + # We try calling it now only, as we don't have any other functions + # to check the outcome by it. Once we add the logger class, we may + # check more. + isc.log.init("root", None, "DEBUG", 50) + + def test_init_defaults(self): + # We try calling it now only, as we don't have any other functions + # to check the outcome by it. Once we add the logger class, we may + # check more. + isc.log.init("root") + + def test_init_notfound(self): + # This should not throw, because the C++ one doesn't. Should we really + # ignore errors like missing file? + isc.log.init("root", "/no/such/file"); + if __name__ == '__main__': unittest.main() From 4e18854902a306ea6ad390eb90a9f43f49c8222b Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Wed, 8 Jun 2011 14:14:15 +0200 Subject: [PATCH 06/22] [trac756] The Logger class wrapper Only initialization and destruction for now, needs to add methods. --- src/lib/python/isc/log/log.cc | 102 +++++++++++++++++++++++ src/lib/python/isc/log/tests/log_test.py | 30 +++++++ 2 files changed, 132 insertions(+) diff --git a/src/lib/python/isc/log/log.cc b/src/lib/python/isc/log/log.cc index 07a490e485..e154ae2f2e 100644 --- a/src/lib/python/isc/log/log.cc +++ b/src/lib/python/isc/log/log.cc @@ -20,6 +20,7 @@ #include #include +#include using namespace isc::log; @@ -184,6 +185,96 @@ PyMethodDef methods[] = { {NULL, NULL, 0, NULL} }; +class LoggerWrapper : public PyObject { +// Everything is public here, as it is accessible only inside this .cc file. +public: + Logger *logger_; +}; + +extern PyTypeObject logger_type; + +int +Logger_init(LoggerWrapper* self, PyObject* args) { + const char* name; + if (!PyArg_ParseTuple(args, "s", &name)) { + return (-1); + } + try { + self->logger_ = new Logger(name); + return (0); + } + catch (const std::exception& e) { + PyErr_SetString(PyExc_RuntimeError, e.what()); + return (-1); + } + catch (...) { + PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception"); + return (-1); + } +} + +void +Logger_destroy(LoggerWrapper* const self) { + delete self->logger_; + self->logger_ = NULL; + Py_TYPE(self)->tp_free(self); +} + +PyMethodDef loggerMethods[] = { + { NULL, NULL, 0, NULL } +}; + +PyTypeObject logger_type = { + PyVarObject_HEAD_INIT(NULL, 0) + "isc.log.Logger", + sizeof(LoggerWrapper), // tp_basicsize + 0, // tp_itemsize + reinterpret_cast(Logger_destroy), // tp_dealloc + NULL, // tp_print + NULL, // tp_getattr + NULL, // tp_setattr + NULL, // tp_reserved + NULL, // tp_repr + NULL, // tp_as_number + NULL, // tp_as_sequence + NULL, // tp_as_mapping + NULL, // tp_hash + NULL, // tp_call + NULL, // tp_str + NULL, // tp_getattro + NULL, // tp_setattro + NULL, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + "Wrapper around the C++ isc::log::Logger class." + "It is not complete, but everything important should be here.", + NULL, // tp_traverse + NULL, // tp_clear + NULL, // tp_richcompare + 0, // tp_weaklistoffset + NULL, // tp_iter + NULL, // tp_iternext + loggerMethods, // tp_methods + NULL, // tp_members + NULL, // tp_getset + NULL, // tp_base + NULL, // tp_dict + NULL, // tp_descr_get + NULL, // tp_descr_set + 0, // tp_dictoffset + reinterpret_cast(Logger_init), // tp_init + NULL, // tp_alloc + PyType_GenericNew, // tp_new + NULL, // tp_free + NULL, // tp_is_gc + NULL, // tp_bases + NULL, // tp_mro + NULL, // tp_cache + NULL, // tp_subclasses + NULL, // tp_weaklist + NULL, // tp_del + 0 // tp_version_tag +}; + PyModuleDef iscLog = { { PyObject_HEAD_INIT(NULL) NULL, 0, NULL}, "log", @@ -207,5 +298,16 @@ PyInit_log(void) { return (NULL); } + if (PyType_Ready(&logger_type) < 0) { + return (NULL); + } + + if (PyModule_AddObject(mod, "Logger", + static_cast(static_cast( + &logger_type))) < 0) { + return (NULL); + } + Py_INCREF(&logger_type); + return (mod); } diff --git a/src/lib/python/isc/log/tests/log_test.py b/src/lib/python/isc/log/tests/log_test.py index 2f4a6b9428..110247fd30 100644 --- a/src/lib/python/isc/log/tests/log_test.py +++ b/src/lib/python/isc/log/tests/log_test.py @@ -52,5 +52,35 @@ class Manager(unittest.TestCase): # ignore errors like missing file? isc.log.init("root", "/no/such/file"); +class Logger(unittest.TestCase): + def tearDown(self): + isc.log.reset() + + def setUp(self): + isc.log.init("root", None, "DEBUG", 50) + + # Checks defaults of the logger + def defaults(self, logger): + self.assertEqual(logger.get_effective_severity(), "DEBUG") + self.assertEqual(logger.get_debug_level(), 50) + + def test_default_severity(self): + logger = isc.log.Logger("child") + self.defaults(logger) + + # Try changing the severities little bit + def test_severity(self): + logger = isc.log.Logger("child") + logger.set_severity('DEBUG', 25) + self.assertEqual(logger.get_effective_severity(), "DEBUG") + self.assertEqual(logger.get_debug_level(), 25) + for sev in ['INFO', 'WARN', 'ERROR', 'FATAL']: + logger.set_severity(sev) + self.assertEqual(logger.get_effective_severity(), sev) + self.assertEqual(logger.get_debug_level(), 0) + # Return to default + logger.set_severity(None) + self.defaults(logger) + if __name__ == '__main__': unittest.main() From a149f9e04c33ce6012a4a3e837c98db6d3074a44 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Wed, 8 Jun 2011 15:44:29 +0200 Subject: [PATCH 07/22] [trac756] Severity manipulation --- src/lib/python/isc/log/log.cc | 101 +++++++++++++++++++++-- src/lib/python/isc/log/tests/log_test.py | 8 +- 2 files changed, 99 insertions(+), 10 deletions(-) diff --git a/src/lib/python/isc/log/log.cc b/src/lib/python/isc/log/log.cc index e154ae2f2e..126774b99b 100644 --- a/src/lib/python/isc/log/log.cc +++ b/src/lib/python/isc/log/log.cc @@ -26,7 +26,6 @@ using namespace isc::log; namespace { - // This is for testing only. The real module will have it always set as // NULL and will use the global dictionary. MessageDictionary* testDictionary = NULL; @@ -45,9 +44,9 @@ setTestDictionary(PyObject*, PyObject* args) { } bool enable(enableI != 0); - delete testDictionary; - testDictionary = NULL; try { + delete testDictionary; + testDictionary = NULL; if (enable) { testDictionary = new MessageDictionary; } @@ -162,21 +161,21 @@ init(PyObject*, PyObject* args) { } PyMethodDef methods[] = { - {"set_test_dictionary", &setTestDictionary, METH_VARARGS, + {"set_test_dictionary", setTestDictionary, METH_VARARGS, "Set or unset testing mode for message dictionary. In testing, " "the create_message and get_message functions work on different " "than the logger-global dictionary, not polluting it."}, - {"create_message", &createMessage, METH_VARARGS, + {"create_message", createMessage, METH_VARARGS, "Creates a new message in the dictionary. You shouldn't need to " "call this directly, it should be called by the generated message " "file. Returns the identifier to be used in logging. The text " "shouldn't be empty."}, - {"get_message", &getMessage, METH_VARARGS, + {"get_message", getMessage, METH_VARARGS, "Get a message. This function is for testing purposes and you don't " "need to call it. It returns None if the message does not exist."}, - {"reset", &reset, METH_VARARGS, + {"reset", reset, METH_NOARGS, "Reset all logging. For testing purposes only, do not use."}, - {"init", &init, METH_VARARGS, + {"init", init, METH_VARARGS, "Run-time initialization. You need to call this before you do any " "logging, to configure the root logger name. You may also provide " "a filename with message translations (or None if you don't want " @@ -220,7 +219,93 @@ Logger_destroy(LoggerWrapper* const self) { Py_TYPE(self)->tp_free(self); } +// The isc::log doesn't contain function to convert this way +const char* +severityToText(const Severity& severity) { + switch (severity) { + case DEFAULT: + return ("DEFAULT"); + case DEBUG: + return ("DEBUG"); + case INFO: + return ("INFO"); + case WARN: + return ("WARN"); + case ERROR: + return ("ERROR"); + case FATAL: + return ("FATAL"); + default: + return (NULL); + } +} + +PyObject* +Logger_getEffectiveSeverity(LoggerWrapper* self, PyObject*) { + try { + return (Py_BuildValue("s", + severityToText( + self->logger_->getEffectiveSeverity()))); + } + catch (const std::exception& e) { + PyErr_SetString(PyExc_RuntimeError, e.what()); + return (NULL); + } + catch (...) { + PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception"); + return (NULL); + } +} + +PyObject* +Logger_getDebugLevel(LoggerWrapper* self, PyObject*) { + try { + return (Py_BuildValue("i", self->logger_->getDebugLevel())); + } + catch (const std::exception& e) { + PyErr_SetString(PyExc_RuntimeError, e.what()); + return (NULL); + } + catch (...) { + PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception"); + return (NULL); + } +} + +PyObject* +Logger_setSeverity(LoggerWrapper* self, PyObject* args) { + const char* severity; + int dbgLevel = 0; + if (!PyArg_ParseTuple(args, "z|i", &severity, &dbgLevel)) { + return (NULL); + } + try { + self->logger_->setSeverity((severity == NULL) ? DEFAULT : + getSeverity(severity), dbgLevel); + } + catch (const std::exception& e) { + PyErr_SetString(PyExc_RuntimeError, e.what()); + return (NULL); + } + catch (...) { + PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception"); + return (NULL); + } + Py_RETURN_NONE; +} + PyMethodDef loggerMethods[] = { + { "get_effective_severity", + reinterpret_cast(Logger_getEffectiveSeverity), + METH_NOARGS, "Returns the effective logging severity as string" }, + { "get_debug_level", reinterpret_cast(Logger_getDebugLevel), + METH_NOARGS, "Returns the current debug level." }, + { "set_severity", + reinterpret_cast(Logger_setSeverity), METH_VARARGS, + "Sets the severity of a logger. The parameters are severity as a " + "string and, optionally, a debug level (integer in range 0-99). " + "The severity may be NULL, in which case an inherited value is taken." + }, { NULL, NULL, 0, NULL } }; diff --git a/src/lib/python/isc/log/tests/log_test.py b/src/lib/python/isc/log/tests/log_test.py index 110247fd30..19bc8440bc 100644 --- a/src/lib/python/isc/log/tests/log_test.py +++ b/src/lib/python/isc/log/tests/log_test.py @@ -62,8 +62,11 @@ class Logger(unittest.TestCase): # Checks defaults of the logger def defaults(self, logger): self.assertEqual(logger.get_effective_severity(), "DEBUG") - self.assertEqual(logger.get_debug_level(), 50) + self.assertEqual(logger.get_debug_level(), 0) + # Because there's a bug in the C++ backend currently. When it's fixed, + # it should no longer fail + @unittest.expectedFailure def test_default_severity(self): logger = isc.log.Logger("child") self.defaults(logger) @@ -80,7 +83,8 @@ class Logger(unittest.TestCase): self.assertEqual(logger.get_debug_level(), 0) # Return to default logger.set_severity(None) - self.defaults(logger) + # The same bug here + #self.defaults(logger) if __name__ == '__main__': unittest.main() From 4fd41636ae9c11a96b3893cbc939fd4854b64b56 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Wed, 8 Jun 2011 16:43:21 +0200 Subject: [PATCH 08/22] [trac756] is****Enabled methods --- src/lib/python/isc/log/log.cc | 76 ++++++++++++++++++++++++ src/lib/python/isc/log/tests/log_test.py | 26 +++++++- 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/src/lib/python/isc/log/log.cc b/src/lib/python/isc/log/log.cc index 126774b99b..006b3c5a2c 100644 --- a/src/lib/python/isc/log/log.cc +++ b/src/lib/python/isc/log/log.cc @@ -294,6 +294,70 @@ Logger_setSeverity(LoggerWrapper* self, PyObject* args) { Py_RETURN_NONE; } +template // Who should remember the pointer-to-method syntax +PyObject* +Logger_isLevelEnabled(LoggerWrapper* self, FPtr function) { + try { + if ((self->logger_->*function)()) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + } + catch (const std::exception& e) { + PyErr_SetString(PyExc_RuntimeError, e.what()); + return (NULL); + } + catch (...) { + PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception"); + return (NULL); + } +} + +PyObject* +Logger_isInfoEnabled(LoggerWrapper* self, PyObject*) { + return (Logger_isLevelEnabled(self, &Logger::isInfoEnabled)); +} + +PyObject* +Logger_isWarnEnabled(LoggerWrapper* self, PyObject*) { + return (Logger_isLevelEnabled(self, &Logger::isWarnEnabled)); +} + +PyObject* +Logger_isErrorEnabled(LoggerWrapper* self, PyObject*) { + return (Logger_isLevelEnabled(self, &Logger::isErrorEnabled)); +} + +PyObject* +Logger_isFatalEnabled(LoggerWrapper* self, PyObject*) { + return (Logger_isLevelEnabled(self, &Logger::isFatalEnabled)); +} + +PyObject* +Logger_isDebugEnabled(LoggerWrapper* self, PyObject* args) { + int level = MIN_DEBUG_LEVEL; + if (!PyArg_ParseTuple(args, "|i", &level)) { + return (NULL); + } + + try { + if (self->logger_->isDebugEnabled(level)) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + } + catch (const std::exception& e) { + PyErr_SetString(PyExc_RuntimeError, e.what()); + return (NULL); + } + catch (...) { + PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception"); + return (NULL); + } +} + PyMethodDef loggerMethods[] = { { "get_effective_severity", reinterpret_cast(Logger_getEffectiveSeverity), @@ -306,6 +370,18 @@ PyMethodDef loggerMethods[] = { "string and, optionally, a debug level (integer in range 0-99). " "The severity may be NULL, in which case an inherited value is taken." }, + { "is_debug_enabled", reinterpret_cast(Logger_isDebugEnabled), + METH_VARARGS, "Returns if the logger would log debug message now. " + "You can provide a desired debug level." + }, + { "is_info_enabled", reinterpret_cast(Logger_isInfoEnabled), + METH_NOARGS, "Returns if the logger would log info message now." }, + { "is_warn_enabled", reinterpret_cast(Logger_isWarnEnabled), + METH_NOARGS, "Returns if the logger would log warn message now." }, + { "is_error_enabled", reinterpret_cast(Logger_isErrorEnabled), + METH_NOARGS, "Returns if the logger would log error message now." }, + { "is_fatal_enabled", reinterpret_cast(Logger_isFatalEnabled), + METH_NOARGS, "Returns if the logger would log fatal message now." }, { NULL, NULL, 0, NULL } }; diff --git a/src/lib/python/isc/log/tests/log_test.py b/src/lib/python/isc/log/tests/log_test.py index 19bc8440bc..c8a1ab1861 100644 --- a/src/lib/python/isc/log/tests/log_test.py +++ b/src/lib/python/isc/log/tests/log_test.py @@ -58,6 +58,7 @@ class Logger(unittest.TestCase): def setUp(self): isc.log.init("root", None, "DEBUG", 50) + self.sevs = ['INFO', 'WARN', 'ERROR', 'FATAL'] # Checks defaults of the logger def defaults(self, logger): @@ -77,7 +78,7 @@ class Logger(unittest.TestCase): logger.set_severity('DEBUG', 25) self.assertEqual(logger.get_effective_severity(), "DEBUG") self.assertEqual(logger.get_debug_level(), 25) - for sev in ['INFO', 'WARN', 'ERROR', 'FATAL']: + for sev in self.sevs: logger.set_severity(sev) self.assertEqual(logger.get_effective_severity(), sev) self.assertEqual(logger.get_debug_level(), 0) @@ -86,5 +87,28 @@ class Logger(unittest.TestCase): # The same bug here #self.defaults(logger) + def test_enabled(self): + logger = isc.log.Logger("child") + self.sevs.insert(0, 'DEBUG') + methods = { + 'DEBUG': logger.is_debug_enabled, + 'INFO': logger.is_info_enabled, + 'WARN': logger.is_warn_enabled, + 'ERROR': logger.is_error_enabled, + 'FATAL': logger.is_fatal_enabled + } + for sev in self.sevs: + logger.set_severity(sev) + enabled = False + for tested in self.sevs: + if tested == sev: + enabled = True + self.assertEqual(methods[tested](), enabled) + logger.set_severity('DEBUG', 50) + self.assertTrue(logger.is_debug_enabled()) + self.assertTrue(logger.is_debug_enabled(0)) + self.assertTrue(logger.is_debug_enabled(50)) + self.assertFalse(logger.is_debug_enabled(99)) + if __name__ == '__main__': unittest.main() From 91920024ba2897735eb1228a17a2cd2bd0f82c61 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Thu, 9 Jun 2011 21:15:34 +0200 Subject: [PATCH 09/22] [trac756] The actual logging output --- configure.ac | 2 + src/lib/python/isc/log/log.cc | 162 +++++++++++++++++- src/lib/python/isc/log/tests/Makefile.am | 4 +- src/lib/python/isc/log/tests/check_output.sh | 3 + src/lib/python/isc/log/tests/console.out | 4 + .../python/isc/log/tests/log_console.py.in | 15 ++ src/lib/python/isc/log/tests/log_test.py | 23 +++ 7 files changed, 209 insertions(+), 4 deletions(-) create mode 100755 src/lib/python/isc/log/tests/check_output.sh create mode 100644 src/lib/python/isc/log/tests/console.out create mode 100755 src/lib/python/isc/log/tests/log_console.py.in diff --git a/configure.ac b/configure.ac index e15d32c2dd..004c2343db 100644 --- a/configure.ac +++ b/configure.ac @@ -884,6 +884,7 @@ AC_OUTPUT([doc/version.ent src/lib/python/isc/config/tests/config_test src/lib/python/isc/cc/tests/cc_test src/lib/python/isc/notify/tests/notify_out_test + src/lib/python/isc/log/tests/log_console.py src/lib/dns/gen-rdatacode.py src/lib/python/bind10_config.py src/lib/dns/tests/testdata/gen-wiredata.py @@ -923,6 +924,7 @@ AC_OUTPUT([doc/version.ent chmod +x src/lib/log/tests/console_test.sh chmod +x src/lib/log/tests/severity_test.sh chmod +x src/lib/util/python/mkpywrapper.py + chmod +x src/lib/python/isc/log/tests/log_console.py chmod +x tests/system/conf.sh ]) AC_OUTPUT diff --git a/src/lib/python/isc/log/log.cc b/src/lib/python/isc/log/log.cc index 006b3c5a2c..cd3dc00b70 100644 --- a/src/lib/python/isc/log/log.cc +++ b/src/lib/python/isc/log/log.cc @@ -22,7 +22,12 @@ #include #include +#include +#include + using namespace isc::log; +using std::string; +using boost::bind; namespace { @@ -358,6 +363,143 @@ Logger_isDebugEnabled(LoggerWrapper* self, PyObject* args) { } } +// To propagate python exceptions trough our code +class InternalError {}; + +string +objectToStr(PyObject* object, bool convert) { + PyObject* cleanup(NULL); + if (convert) { + object = cleanup = PyObject_Str(object); + if (object == NULL) { + throw InternalError(); + } + } + const char* value; + PyObject* tuple(Py_BuildValue("(O)", object)); + if (tuple == NULL) { + if (cleanup != NULL) { + Py_DECREF(cleanup); + } + throw InternalError(); + } + + if (!PyArg_ParseTuple(tuple, "s", &value)) { + Py_DECREF(tuple); + if (cleanup != NULL) { + Py_DECREF(cleanup); + } + throw InternalError(); + } + string result(value); + Py_DECREF(tuple); + if (cleanup != NULL) { + Py_DECREF(cleanup); + } + return (result); +} + +// Generic function to output the logging message. Called by the real functions. +template +PyObject* +Logger_performOutput(Function function, PyObject* args, bool dbgLevel) { + try { + Py_ssize_t number(PyObject_Length(args)); + if (number < 0) { + return (NULL); + } + + // Which argument is the first to format? + size_t start(1); + if (dbgLevel) { + start ++; + } + + if (number < start) { + return (PyErr_Format(PyExc_TypeError, "Too few arguments to " + "logging call, at last %zu needed and %zd " + "given", start, number)); + } + + // Extract the fixed arguments + PyObject *midO(PySequence_GetItem(args, start - 1)); + if (midO == NULL) { + return (NULL); + } + string mid(objectToStr(midO, false)); + long dbg(0); + if (dbgLevel) { + PyObject *dbgO(PySequence_GetItem(args, 0)); + if (dbgO == NULL) { + return (NULL); + } + dbg = PyLong_AsLong(dbgO); + if (PyErr_Occurred()) { + return (NULL); + } + } + + // We create the logging message right now. If we fail to convert a + // parameter to string, at last the part that we already did will + // be output + Logger::Formatter formatter(function(dbg, mid.c_str())); + + // Now process the rest of parameters, convert each to string and put + // into the formatter. It will print itself in the end. + for (size_t i(start); i < number; ++ i) { + PyObject* param(PySequence_GetItem(args, i)); + if (param == NULL) { + return (NULL); + } + formatter = formatter.arg(objectToStr(param, true)); + } + Py_RETURN_NONE; + } + catch (const InternalError&) { + return (NULL); + } + catch (const std::exception& e) { + PyErr_SetString(PyExc_RuntimeError, e.what()); + return (NULL); + } + catch (...) { + PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception"); + return (NULL); + } +} + +// Now map the functions into the performOutput. I wish C++ could do +// functional programming. +PyObject* +Logger_debug(LoggerWrapper* self, PyObject* args) { + return (Logger_performOutput(bind(&Logger::debug, self->logger_, _1, _2), + args, true)); +} + +PyObject* +Logger_info(LoggerWrapper* self, PyObject* args) { + return (Logger_performOutput(bind(&Logger::info, self->logger_, _2), + args, false)); +} + +PyObject* +Logger_warn(LoggerWrapper* self, PyObject* args) { + return (Logger_performOutput(bind(&Logger::warn, self->logger_, _2), + args, false)); +} + +PyObject* +Logger_error(LoggerWrapper* self, PyObject* args) { + return (Logger_performOutput(bind(&Logger::error, self->logger_, _2), + args, false)); +} + +PyObject* +Logger_fatal(LoggerWrapper* self, PyObject* args) { + return (Logger_performOutput(bind(&Logger::fatal, self->logger_, _2), + args, false)); +} + PyMethodDef loggerMethods[] = { { "get_effective_severity", reinterpret_cast(Logger_getEffectiveSeverity), @@ -369,11 +511,10 @@ PyMethodDef loggerMethods[] = { "Sets the severity of a logger. The parameters are severity as a " "string and, optionally, a debug level (integer in range 0-99). " "The severity may be NULL, in which case an inherited value is taken." - }, + }, { "is_debug_enabled", reinterpret_cast(Logger_isDebugEnabled), METH_VARARGS, "Returns if the logger would log debug message now. " - "You can provide a desired debug level." - }, + "You can provide a desired debug level." }, { "is_info_enabled", reinterpret_cast(Logger_isInfoEnabled), METH_NOARGS, "Returns if the logger would log info message now." }, { "is_warn_enabled", reinterpret_cast(Logger_isWarnEnabled), @@ -382,6 +523,21 @@ PyMethodDef loggerMethods[] = { METH_NOARGS, "Returns if the logger would log error message now." }, { "is_fatal_enabled", reinterpret_cast(Logger_isFatalEnabled), METH_NOARGS, "Returns if the logger would log fatal message now." }, + { "debug", reinterpret_cast(Logger_debug), METH_VARARGS, + "Logs a debug-severity message. It takes the debug level, message ID " + "and any number of stringifiable arguments to the message." }, + { "info", reinterpret_cast(Logger_info), METH_VARARGS, + "Logs a info-severity message. It taskes the message ID and any " + "number of stringifiable arguments to the message." }, + { "warn", reinterpret_cast(Logger_warn), METH_VARARGS, + "Logs a warn-severity message. It taskes the message ID and any " + "number of stringifiable arguments to the message." }, + { "error", reinterpret_cast(Logger_error), METH_VARARGS, + "Logs a error-severity message. It taskes the message ID and any " + "number of stringifiable arguments to the message." }, + { "fatal", reinterpret_cast(Logger_fatal), METH_VARARGS, + "Logs a fatal-severity message. It taskes the message ID and any " + "number of stringifiable arguments to the message." }, { NULL, NULL, 0, NULL } }; diff --git a/src/lib/python/isc/log/tests/Makefile.am b/src/lib/python/isc/log/tests/Makefile.am index fc00d0d90a..f2825cba5c 100644 --- a/src/lib/python/isc/log/tests/Makefile.am +++ b/src/lib/python/isc/log/tests/Makefile.am @@ -1,9 +1,11 @@ PYCOVERAGE_RUN = @PYCOVERAGE_RUN@ PYTESTS = log_test.py -EXTRA_DIST = $(PYTESTS) +EXTRA_DIST = $(PYTESTS) log_console.py.in console.out check_output.sh # test using command-line arguments, so use check-local target instead of TESTS check-local: + env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/python/isc/log \ + $(abs_srcdir)/check_output.sh $(abs_builddir)/log_console.py $(abs_srcdir)/console.out if ENABLE_PYTHON_COVERAGE touch $(abs_top_srcdir)/.coverage rm -f .coverage diff --git a/src/lib/python/isc/log/tests/check_output.sh b/src/lib/python/isc/log/tests/check_output.sh new file mode 100755 index 0000000000..32146afcfc --- /dev/null +++ b/src/lib/python/isc/log/tests/check_output.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +"$1" 2>&1 | cut -d\ -f3- | diff - "$2" 1>&2 diff --git a/src/lib/python/isc/log/tests/console.out b/src/lib/python/isc/log/tests/console.out new file mode 100644 index 0000000000..d3c67702ea --- /dev/null +++ b/src/lib/python/isc/log/tests/console.out @@ -0,0 +1,4 @@ +INFO [test.output] MSG_ID, Message with list [1, 2, 3, 4] +WARN [test.output] DIFFERENT, Different message +FATAL [test.output] MSG_ID, Message with 2 1 +DEBUG [test.output] MSG_ID, Message with 3 2 diff --git a/src/lib/python/isc/log/tests/log_console.py.in b/src/lib/python/isc/log/tests/log_console.py.in new file mode 100755 index 0000000000..a5b2256851 --- /dev/null +++ b/src/lib/python/isc/log/tests/log_console.py.in @@ -0,0 +1,15 @@ +#!@PYTHON@ + +import isc.log +# This would come from a dictionary in real life +MSG_ID = isc.log.create_message("MSG_ID", "Message with %2 %1") +DIFFERENT = isc.log.create_message("DIFFERENT", "Different message") +isc.log.init("test") +logger = isc.log.Logger("output") + +logger.debug(20, MSG_ID, "test", "no output") +logger.info(MSG_ID, [1, 2, 3, 4], "list") +logger.warn(DIFFERENT) +logger.fatal(MSG_ID, 1, 2) +logger.setSeverity("DEBUG", 99) +logger.debug(1, MSG_ID, 2, 3) diff --git a/src/lib/python/isc/log/tests/log_test.py b/src/lib/python/isc/log/tests/log_test.py index c8a1ab1861..946d45ffe0 100644 --- a/src/lib/python/isc/log/tests/log_test.py +++ b/src/lib/python/isc/log/tests/log_test.py @@ -110,5 +110,28 @@ class Logger(unittest.TestCase): self.assertTrue(logger.is_debug_enabled(50)) self.assertFalse(logger.is_debug_enabled(99)) + def test_invalid_params(self): + """ + Tests invalid arguments for logging functions. The output is tested + in check_output.sh. + """ + logger = isc.log.Logger("child") + methods = [ + logger.info, + logger.warn, + logger.error, + logger.fatal + ] + for meth in methods: + # Not enough arguments + self.assertRaises(TypeError, meth) + # Bad type + self.assertRaises(TypeError, meth, 1) + # Too few arguments + self.assertRaises(TypeError, logger.debug, 42) + self.assertRaises(TypeError, logger.debug) + # Bad type + self.assertRaises(TypeError, logger.debug, "42", "hello") + if __name__ == '__main__': unittest.main() From c55ce18325b71ece62d213ef4ab60e6c95c07da8 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Fri, 10 Jun 2011 13:05:10 +0200 Subject: [PATCH 10/22] [trac756] Fix test I fixed it in the .py file previously, which didn't survive O:-) --- src/lib/python/isc/log/tests/log_console.py.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/python/isc/log/tests/log_console.py.in b/src/lib/python/isc/log/tests/log_console.py.in index a5b2256851..af05f61b75 100755 --- a/src/lib/python/isc/log/tests/log_console.py.in +++ b/src/lib/python/isc/log/tests/log_console.py.in @@ -11,5 +11,5 @@ logger.debug(20, MSG_ID, "test", "no output") logger.info(MSG_ID, [1, 2, 3, 4], "list") logger.warn(DIFFERENT) logger.fatal(MSG_ID, 1, 2) -logger.setSeverity("DEBUG", 99) +logger.set_severity("DEBUG", 99) logger.debug(1, MSG_ID, 2, 3) From f28bffcf3e0369b89631df178865a2de00145f97 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Fri, 10 Jun 2011 13:18:44 +0200 Subject: [PATCH 11/22] [trac756] Adapt to changed parameter order --- src/lib/python/isc/log/log.cc | 10 +++++----- src/lib/python/isc/log/tests/log_test.py | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lib/python/isc/log/log.cc b/src/lib/python/isc/log/log.cc index cd3dc00b70..957982631f 100644 --- a/src/lib/python/isc/log/log.cc +++ b/src/lib/python/isc/log/log.cc @@ -147,12 +147,12 @@ init(PyObject*, PyObject* args) { const char* file(NULL); const char* severity("INFO"); int dbglevel(0); - if (!PyArg_ParseTuple(args, "s|zsi", &root, &file, &severity, &dbglevel)) { + if (!PyArg_ParseTuple(args, "s|siz", &root, &severity, &dbglevel, &file)) { return (NULL); } try { - LoggerManager::init(root, file, getSeverity(severity), dbglevel); + LoggerManager::init(root, getSeverity(severity), dbglevel, file); } catch (const std::exception& e) { PyErr_SetString(PyExc_RuntimeError, e.what()); @@ -183,9 +183,9 @@ PyMethodDef methods[] = { {"init", init, METH_VARARGS, "Run-time initialization. You need to call this before you do any " "logging, to configure the root logger name. You may also provide " - "a filename with message translations (or None if you don't want " - "any), logging severity (one of 'DEBUG', 'INFO', 'WARN', 'ERROR' or " - "'FATAL') and a debug level (integer in the range 0-99)."}, + "logging severity (one of 'DEBUG', 'INFO', 'WARN', 'ERROR' or " + "'FATAL'), a debug level (integer in the range 0-99) and a file name " + "of a dictionary with message text translations."}, {NULL, NULL, 0, NULL} }; diff --git a/src/lib/python/isc/log/tests/log_test.py b/src/lib/python/isc/log/tests/log_test.py index 946d45ffe0..1d585b898d 100644 --- a/src/lib/python/isc/log/tests/log_test.py +++ b/src/lib/python/isc/log/tests/log_test.py @@ -39,7 +39,7 @@ class Manager(unittest.TestCase): # We try calling it now only, as we don't have any other functions # to check the outcome by it. Once we add the logger class, we may # check more. - isc.log.init("root", None, "DEBUG", 50) + isc.log.init("root", "DEBUG", 50, None) def test_init_defaults(self): # We try calling it now only, as we don't have any other functions @@ -50,14 +50,14 @@ class Manager(unittest.TestCase): def test_init_notfound(self): # This should not throw, because the C++ one doesn't. Should we really # ignore errors like missing file? - isc.log.init("root", "/no/such/file"); + isc.log.init("root", "INFO", 0, "/no/such/file"); class Logger(unittest.TestCase): def tearDown(self): isc.log.reset() def setUp(self): - isc.log.init("root", None, "DEBUG", 50) + isc.log.init("root", "DEBUG", 50) self.sevs = ['INFO', 'WARN', 'ERROR', 'FATAL'] # Checks defaults of the logger From 3cf7f4bf3f7c6947bab97f269172236dea5b9d52 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Fri, 10 Jun 2011 13:21:05 +0200 Subject: [PATCH 12/22] [trac756] Enable the previously-buggy test --- src/lib/python/isc/log/tests/log_test.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/lib/python/isc/log/tests/log_test.py b/src/lib/python/isc/log/tests/log_test.py index 1d585b898d..23b62b70e9 100644 --- a/src/lib/python/isc/log/tests/log_test.py +++ b/src/lib/python/isc/log/tests/log_test.py @@ -65,9 +65,6 @@ class Logger(unittest.TestCase): self.assertEqual(logger.get_effective_severity(), "DEBUG") self.assertEqual(logger.get_debug_level(), 0) - # Because there's a bug in the C++ backend currently. When it's fixed, - # it should no longer fail - @unittest.expectedFailure def test_default_severity(self): logger = isc.log.Logger("child") self.defaults(logger) @@ -84,8 +81,7 @@ class Logger(unittest.TestCase): self.assertEqual(logger.get_debug_level(), 0) # Return to default logger.set_severity(None) - # The same bug here - #self.defaults(logger) + self.defaults(logger) def test_enabled(self): logger = isc.log.Logger("child") From 2826df63af5ce079b537fb8beaa09b0138b7c308 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Fri, 10 Jun 2011 13:23:11 +0200 Subject: [PATCH 13/22] [trac756] Effective debug level --- src/lib/python/isc/log/log.cc | 7 ++++--- src/lib/python/isc/log/tests/log_test.py | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/lib/python/isc/log/log.cc b/src/lib/python/isc/log/log.cc index 957982631f..6bcaddacac 100644 --- a/src/lib/python/isc/log/log.cc +++ b/src/lib/python/isc/log/log.cc @@ -263,9 +263,9 @@ Logger_getEffectiveSeverity(LoggerWrapper* self, PyObject*) { } PyObject* -Logger_getDebugLevel(LoggerWrapper* self, PyObject*) { +Logger_getEffectiveDebugLevel(LoggerWrapper* self, PyObject*) { try { - return (Py_BuildValue("i", self->logger_->getDebugLevel())); + return (Py_BuildValue("i", self->logger_->getEffectiveDebugLevel())); } catch (const std::exception& e) { PyErr_SetString(PyExc_RuntimeError, e.what()); @@ -504,7 +504,8 @@ PyMethodDef loggerMethods[] = { { "get_effective_severity", reinterpret_cast(Logger_getEffectiveSeverity), METH_NOARGS, "Returns the effective logging severity as string" }, - { "get_debug_level", reinterpret_cast(Logger_getDebugLevel), + { "get_effective_debug_level", + reinterpret_cast(Logger_getEffectiveDebugLevel), METH_NOARGS, "Returns the current debug level." }, { "set_severity", reinterpret_cast(Logger_setSeverity), METH_VARARGS, diff --git a/src/lib/python/isc/log/tests/log_test.py b/src/lib/python/isc/log/tests/log_test.py index 23b62b70e9..a463d59e02 100644 --- a/src/lib/python/isc/log/tests/log_test.py +++ b/src/lib/python/isc/log/tests/log_test.py @@ -63,7 +63,7 @@ class Logger(unittest.TestCase): # Checks defaults of the logger def defaults(self, logger): self.assertEqual(logger.get_effective_severity(), "DEBUG") - self.assertEqual(logger.get_debug_level(), 0) + self.assertEqual(logger.get_effective_debug_level(), 50) def test_default_severity(self): logger = isc.log.Logger("child") @@ -74,11 +74,11 @@ class Logger(unittest.TestCase): logger = isc.log.Logger("child") logger.set_severity('DEBUG', 25) self.assertEqual(logger.get_effective_severity(), "DEBUG") - self.assertEqual(logger.get_debug_level(), 25) + self.assertEqual(logger.get_effective_debug_level(), 25) for sev in self.sevs: logger.set_severity(sev) self.assertEqual(logger.get_effective_severity(), sev) - self.assertEqual(logger.get_debug_level(), 0) + self.assertEqual(logger.get_effective_debug_level(), 0) # Return to default logger.set_severity(None) self.defaults(logger) From 576f337f42e5c72aec48d8ea1d36ab5059588301 Mon Sep 17 00:00:00 2001 From: Jelte Jansen Date: Wed, 15 Jun 2011 09:51:57 +0200 Subject: [PATCH 14/22] [trac756] a few trivial typos --- src/lib/python/isc/log/log.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/python/isc/log/log.cc b/src/lib/python/isc/log/log.cc index 6bcaddacac..e871768249 100644 --- a/src/lib/python/isc/log/log.cc +++ b/src/lib/python/isc/log/log.cc @@ -417,7 +417,7 @@ Logger_performOutput(Function function, PyObject* args, bool dbgLevel) { if (number < start) { return (PyErr_Format(PyExc_TypeError, "Too few arguments to " - "logging call, at last %zu needed and %zd " + "logging call, at least %zu needed and %zd " "given", start, number)); } @@ -440,7 +440,7 @@ Logger_performOutput(Function function, PyObject* args, bool dbgLevel) { } // We create the logging message right now. If we fail to convert a - // parameter to string, at last the part that we already did will + // parameter to string, at least the part that we already did will // be output Logger::Formatter formatter(function(dbg, mid.c_str())); @@ -607,7 +607,7 @@ PyModuleDef iscLog = { NULL }; -} +} // end anonymous namespace PyMODINIT_FUNC PyInit_log(void) { From 9723ecc53f8afd751d66d4e2db24f8fd05ffb467 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Wed, 15 Jun 2011 11:32:47 +0200 Subject: [PATCH 15/22] [trac756] Remove old comment --- src/lib/python/isc/log/log.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib/python/isc/log/log.cc b/src/lib/python/isc/log/log.cc index e871768249..68cf213c2a 100644 --- a/src/lib/python/isc/log/log.cc +++ b/src/lib/python/isc/log/log.cc @@ -135,8 +135,6 @@ getMessage(PyObject*, PyObject* args) { PyObject* reset(PyObject*, PyObject*) { - // TODO Should we check we got exactly 0 arguments? - // But who cares, it's testing function only LoggerManager::reset(); Py_RETURN_NONE; } From f7a8e38c733ab5695bda72b7b69a803c8d98c80b Mon Sep 17 00:00:00 2001 From: Stephen Morris Date: Wed, 15 Jun 2011 16:59:55 +0100 Subject: [PATCH 16/22] [master] Add missing BOOST_INCLUDE to compiler flags --- src/lib/acl/tests/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/acl/tests/Makefile.am b/src/lib/acl/tests/Makefile.am index 5c0cdfc577..a6e90f7974 100644 --- a/src/lib/acl/tests/Makefile.am +++ b/src/lib/acl/tests/Makefile.am @@ -1,4 +1,5 @@ AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib +AM_CPPFLAGS += $(BOOST_INCLUDES) TESTS = if HAVE_GTEST From 179a2105dc0a9c9341d4347b711b62c2bbb9ccfb Mon Sep 17 00:00:00 2001 From: Stephen Morris Date: Wed, 15 Jun 2011 17:40:28 +0100 Subject: [PATCH 17/22] [master] Add "." to SUBDIRS Allows "make check" to work without a preceding "make" --- src/lib/python/isc/log/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/python/isc/log/Makefile.am b/src/lib/python/isc/log/Makefile.am index ede3cbf9eb..1abfc17da0 100644 --- a/src/lib/python/isc/log/Makefile.am +++ b/src/lib/python/isc/log/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = tests +SUBDIRS = . tests AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib AM_CPPFLAGS += $(BOOST_INCLUDES) From e1bf2fce994c07e02466016d94007e509f2fe478 Mon Sep 17 00:00:00 2001 From: JINMEI Tatuya Date: Wed, 15 Jun 2011 10:38:28 -0700 Subject: [PATCH 18/22] [master] fixed test error due to missing DYLD path for MacOS. patch reviewed on jabber. --- src/lib/python/isc/log/tests/Makefile.am | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/lib/python/isc/log/tests/Makefile.am b/src/lib/python/isc/log/tests/Makefile.am index f2825cba5c..0eacbb1d9f 100644 --- a/src/lib/python/isc/log/tests/Makefile.am +++ b/src/lib/python/isc/log/tests/Makefile.am @@ -2,8 +2,16 @@ PYCOVERAGE_RUN = @PYCOVERAGE_RUN@ PYTESTS = log_test.py EXTRA_DIST = $(PYTESTS) log_console.py.in console.out check_output.sh +# If necessary (rare cases), explicitly specify paths to dynamic libraries +# required by loadable python modules. +LIBRARY_PATH_PLACEHOLDER = +if SET_ENV_LIBRARY_PATH +LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/log/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$$$(ENV_LIBRARY_PATH) +endif + # test using command-line arguments, so use check-local target instead of TESTS check-local: + $(LIBRARY_PATH_PLACEHOLDER) \ env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/python/isc/log \ $(abs_srcdir)/check_output.sh $(abs_builddir)/log_console.py $(abs_srcdir)/console.out if ENABLE_PYTHON_COVERAGE @@ -13,6 +21,7 @@ if ENABLE_PYTHON_COVERAGE endif for pytest in $(PYTESTS) ; do \ echo Running test: $$pytest ; \ - env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/python/isc/log \ + $(LIBRARY_PATH_PLACEHOLDER) \ + env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/python/isc/log:$(abs_top_builddir)/src/lib/log/python/.libs \ $(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \ done From e31eaa10fc2fc2730311596b7ee4ac16050efe62 Mon Sep 17 00:00:00 2001 From: Jelte Jansen Date: Thu, 16 Jun 2011 15:07:46 +0200 Subject: [PATCH 19/22] [trac1017] move unnecessary .in files and fix build/srcdir --- configure.ac | 6 ------ .../stats/{stats-httpd-xml.tpl.in => stats-httpd-xml.tpl} | 0 .../stats/{stats-httpd-xsd.tpl.in => stats-httpd-xsd.tpl} | 0 .../stats/{stats-httpd-xsl.tpl.in => stats-httpd-xsl.tpl} | 0 src/bin/stats/{stats-httpd.spec.in => stats-httpd.spec} | 0 src/bin/stats/{stats-schema.spec.in => stats-schema.spec} | 0 src/bin/stats/{stats.spec.in => stats.spec} | 0 src/bin/xfrout/tests/Makefile.am | 2 +- 8 files changed, 1 insertion(+), 7 deletions(-) rename src/bin/stats/{stats-httpd-xml.tpl.in => stats-httpd-xml.tpl} (100%) rename src/bin/stats/{stats-httpd-xsd.tpl.in => stats-httpd-xsd.tpl} (100%) rename src/bin/stats/{stats-httpd-xsl.tpl.in => stats-httpd-xsl.tpl} (100%) rename src/bin/stats/{stats-httpd.spec.in => stats-httpd.spec} (100%) rename src/bin/stats/{stats-schema.spec.in => stats-schema.spec} (100%) rename src/bin/stats/{stats.spec.in => stats.spec} (100%) diff --git a/configure.ac b/configure.ac index c4857b084e..b2f2dd785d 100644 --- a/configure.ac +++ b/configure.ac @@ -858,12 +858,6 @@ AC_OUTPUT([doc/version.ent src/bin/zonemgr/run_b10-zonemgr.sh src/bin/stats/stats.py src/bin/stats/stats_httpd.py - src/bin/stats/stats.spec - src/bin/stats/stats-schema.spec - src/bin/stats/stats-httpd.spec - src/bin/stats/stats-httpd-xml.tpl - src/bin/stats/stats-httpd-xsd.tpl - src/bin/stats/stats-httpd-xsl.tpl src/bin/bind10/bind10.py src/bin/bind10/run_bind10.sh src/bin/bind10/tests/bind10_test.py diff --git a/src/bin/stats/stats-httpd-xml.tpl.in b/src/bin/stats/stats-httpd-xml.tpl similarity index 100% rename from src/bin/stats/stats-httpd-xml.tpl.in rename to src/bin/stats/stats-httpd-xml.tpl diff --git a/src/bin/stats/stats-httpd-xsd.tpl.in b/src/bin/stats/stats-httpd-xsd.tpl similarity index 100% rename from src/bin/stats/stats-httpd-xsd.tpl.in rename to src/bin/stats/stats-httpd-xsd.tpl diff --git a/src/bin/stats/stats-httpd-xsl.tpl.in b/src/bin/stats/stats-httpd-xsl.tpl similarity index 100% rename from src/bin/stats/stats-httpd-xsl.tpl.in rename to src/bin/stats/stats-httpd-xsl.tpl diff --git a/src/bin/stats/stats-httpd.spec.in b/src/bin/stats/stats-httpd.spec similarity index 100% rename from src/bin/stats/stats-httpd.spec.in rename to src/bin/stats/stats-httpd.spec diff --git a/src/bin/stats/stats-schema.spec.in b/src/bin/stats/stats-schema.spec similarity index 100% rename from src/bin/stats/stats-schema.spec.in rename to src/bin/stats/stats-schema.spec diff --git a/src/bin/stats/stats.spec.in b/src/bin/stats/stats.spec similarity index 100% rename from src/bin/stats/stats.spec.in rename to src/bin/stats/stats.spec diff --git a/src/bin/xfrout/tests/Makefile.am b/src/bin/xfrout/tests/Makefile.am index 11916afbfe..18503e78d9 100644 --- a/src/bin/xfrout/tests/Makefile.am +++ b/src/bin/xfrout/tests/Makefile.am @@ -20,5 +20,5 @@ endif echo Running test: $$pytest ; \ env PYTHONPATH=$(abs_top_builddir)/src/bin/xfrout:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/lib/util/io/.libs \ $(LIBRARY_PATH_PLACEHOLDER) \ - $(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \ + $(PYCOVERAGE_RUN) $(abs_builddir)/$$pytest || exit ; \ done From 8f95286e55b815323110f79d92f338878930509f Mon Sep 17 00:00:00 2001 From: Jelte Jansen Date: Thu, 16 Jun 2011 17:54:49 +0200 Subject: [PATCH 20/22] [trac1018] logging checking code and spec weren't installed --- src/bin/cfgmgr/plugins/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bin/cfgmgr/plugins/Makefile.am b/src/bin/cfgmgr/plugins/Makefile.am index 64f9dc3719..d1e0f70664 100644 --- a/src/bin/cfgmgr/plugins/Makefile.am +++ b/src/bin/cfgmgr/plugins/Makefile.am @@ -4,3 +4,4 @@ EXTRA_DIST += logging.spec b10logging.py config_plugindir = @prefix@/share/@PACKAGE@/config_plugins config_plugin_DATA = tsig_keys.py tsig_keys.spec +config_plugin_DATA = b10logging.py logging.spec From 69da5b8b1b3ed9f6c6e21cae8a8a86c8fbf83a76 Mon Sep 17 00:00:00 2001 From: Jelte Jansen Date: Thu, 16 Jun 2011 18:06:42 +0200 Subject: [PATCH 21/22] [trac1018] as jeremy noted, should be += of course --- src/bin/cfgmgr/plugins/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/cfgmgr/plugins/Makefile.am b/src/bin/cfgmgr/plugins/Makefile.am index d1e0f70664..25f5074d1b 100644 --- a/src/bin/cfgmgr/plugins/Makefile.am +++ b/src/bin/cfgmgr/plugins/Makefile.am @@ -4,4 +4,4 @@ EXTRA_DIST += logging.spec b10logging.py config_plugindir = @prefix@/share/@PACKAGE@/config_plugins config_plugin_DATA = tsig_keys.py tsig_keys.spec -config_plugin_DATA = b10logging.py logging.spec +config_plugin_DATA += b10logging.py logging.spec From 8cad081427cd8326318ef1a0dc81c1eefaf73d29 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Thu, 16 Jun 2011 13:28:22 -0500 Subject: [PATCH 22/22] [master] fix twpo misspelling typos --- src/bin/resolver/resolverdef.mes | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/resolver/resolverdef.mes b/src/bin/resolver/resolverdef.mes index bb89cfa8cd..47433a4259 100644 --- a/src/bin/resolver/resolverdef.mes +++ b/src/bin/resolver/resolverdef.mes @@ -118,7 +118,7 @@ of the body of the message failed due to some non-protocol related reason (although the parsing of the header succeeded). The message parameters give a textual description of the problem and the RCODE returned. -% PRINTMSG print message command, aeguments are: %1 +% PRINTMSG print message command, arguments are: %1 This message is logged when a "print_message" command is received over the command channel. @@ -169,7 +169,7 @@ resolver gives up trying to resolve a query. Retry count: the number of times the resolver will retry a query to an upstream server if it gets a timeout. The client and lookup timeouts require a bit more explanation. The -resolution of the clent query might require a large number of queries to +resolution of the client query might require a large number of queries to upstream nameservers. Even if none of these queries timeout, the total time taken to perform all the queries may exceed the client timeout. When this happens, a SERVFAIL is returned to the client, but the resolver continues