BIND 10 master, updated. 62318bb5e15a45164d9cba4a03c9e5583e0b6aa3 Merge branch 'work/pylog'
BIND 10 source code commits
bind10-changes at lists.isc.org
Wed Jun 15 13:18:47 UTC 2011
The branch, master has been updated
via 62318bb5e15a45164d9cba4a03c9e5583e0b6aa3 (commit)
via 9723ecc53f8afd751d66d4e2db24f8fd05ffb467 (commit)
via 576f337f42e5c72aec48d8ea1d36ab5059588301 (commit)
via 2826df63af5ce079b537fb8beaa09b0138b7c308 (commit)
via 3cf7f4bf3f7c6947bab97f269172236dea5b9d52 (commit)
via f28bffcf3e0369b89631df178865a2de00145f97 (commit)
via 2a81a3ad5a7fa790d2b03845b81380f395fb5ac8 (commit)
via c55ce18325b71ece62d213ef4ab60e6c95c07da8 (commit)
via 91920024ba2897735eb1228a17a2cd2bd0f82c61 (commit)
via 4fd41636ae9c11a96b3893cbc939fd4854b64b56 (commit)
via a149f9e04c33ce6012a4a3e837c98db6d3074a44 (commit)
via 4e18854902a306ea6ad390eb90a9f43f49c8222b (commit)
via 88119987e9f33fa12243eacee75bd9ec4c99f936 (commit)
via c9abaf3a9e3e78a875e9722649615339dfb75047 (commit)
via 70d184ad5dac430b1591166893689ecb5b774777 (commit)
via a215fa328b934f3d140e433725b2d7a540b826f5 (commit)
via 717534f5a10d288081a0d8b40644794cc1b38861 (commit)
from f3813c74f58f13c2b93859f0b4e07788af631960 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 62318bb5e15a45164d9cba4a03c9e5583e0b6aa3
Merge: f3813c74f58f13c2b93859f0b4e07788af631960 9723ecc53f8afd751d66d4e2db24f8fd05ffb467
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Wed Jun 15 15:06:16 2011 +0200
Merge branch 'work/pylog'
commit 9723ecc53f8afd751d66d4e2db24f8fd05ffb467
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Wed Jun 15 11:32:47 2011 +0200
[trac756] Remove old comment
commit 576f337f42e5c72aec48d8ea1d36ab5059588301
Author: Jelte Jansen <jelte at isc.org>
Date: Wed Jun 15 09:51:57 2011 +0200
[trac756] a few trivial typos
commit 2826df63af5ce079b537fb8beaa09b0138b7c308
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Fri Jun 10 13:23:11 2011 +0200
[trac756] Effective debug level
commit 3cf7f4bf3f7c6947bab97f269172236dea5b9d52
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Fri Jun 10 13:21:05 2011 +0200
[trac756] Enable the previously-buggy test
commit f28bffcf3e0369b89631df178865a2de00145f97
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Fri Jun 10 13:18:44 2011 +0200
[trac756] Adapt to changed parameter order
commit 2a81a3ad5a7fa790d2b03845b81380f395fb5ac8
Merge: c55ce18325b71ece62d213ef4ab60e6c95c07da8 9c2b48c4baccba83732e2586eff2b7ee64c63ac9
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Fri Jun 10 13:06:27 2011 +0200
Merge branch 'master' into work/pylog
commit c55ce18325b71ece62d213ef4ab60e6c95c07da8
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Fri Jun 10 13:05:10 2011 +0200
[trac756] Fix test
I fixed it in the .py file previously, which didn't survive O:-)
commit 91920024ba2897735eb1228a17a2cd2bd0f82c61
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Thu Jun 9 21:15:34 2011 +0200
[trac756] The actual logging output
commit 4fd41636ae9c11a96b3893cbc939fd4854b64b56
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Wed Jun 8 16:43:21 2011 +0200
[trac756] is****Enabled methods
commit a149f9e04c33ce6012a4a3e837c98db6d3074a44
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Wed Jun 8 15:44:29 2011 +0200
[trac756] Severity manipulation
commit 4e18854902a306ea6ad390eb90a9f43f49c8222b
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Wed Jun 8 14:14:15 2011 +0200
[trac756] The Logger class wrapper
Only initialization and destruction for now, needs to add methods.
commit 88119987e9f33fa12243eacee75bd9ec4c99f936
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Jun 7 15:59:49 2011 +0200
[trac756] Logger initialization
commit c9abaf3a9e3e78a875e9722649615339dfb75047
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Jun 7 12:35:30 2011 +0200
[trac756] Adding messages to the dictionary
commit 70d184ad5dac430b1591166893689ecb5b774777
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Mon Jun 6 17:43:28 2011 +0200
[trac756] Test the module can be loaded
With a nasty trick to be located during tests.
commit a215fa328b934f3d140e433725b2d7a540b826f5
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Mon Jun 6 17:09:22 2011 +0200
[trac756] Create the module
It's still empty now, but it at last installs into the correct directory
and loads.
commit 717534f5a10d288081a0d8b40644794cc1b38861
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Mon Jun 6 16:06:00 2011 +0200
[trac756] Get rid of original isc.log module
-----------------------------------------------------------------------
Summary of changes:
configure.ac | 3 +-
src/bin/xfrout/tests/xfrout_test.py.in | 6 +-
src/bin/xfrout/xfrout.py.in | 81 ++--
src/lib/log/compiler/message.cc | 4 +-
src/lib/python/isc/__init__.py | 1 -
src/lib/python/isc/log/Makefile.am | 20 +-
src/lib/python/isc/log/__init__.py | 30 ++-
src/lib/python/isc/log/log.cc | 629 ++++++++++++++++++++++++
src/lib/python/isc/log/log.py | 280 -----------
src/lib/python/isc/log/tests/Makefile.am | 6 +-
src/lib/python/isc/log/tests/check_output.sh | 3 +
src/lib/python/isc/log/tests/console.out | 4 +
src/lib/python/isc/log/tests/log_console.py.in | 15 +
src/lib/python/isc/log/tests/log_test.in | 26 -
src/lib/python/isc/log/tests/log_test.py | 320 ++++--------
15 files changed, 856 insertions(+), 572 deletions(-)
create mode 100644 src/lib/python/isc/log/log.cc
delete mode 100644 src/lib/python/isc/log/log.py
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
delete mode 100644 src/lib/python/isc/log/tests/log_test.in
-----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index 43016d0..c4857b0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -885,8 +885,8 @@ 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/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
@@ -928,6 +928,7 @@ AC_OUTPUT([doc/version.ent
chmod +x src/lib/log/tests/destination_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/bin/xfrout/tests/xfrout_test.py.in b/src/bin/xfrout/tests/xfrout_test.py.in
index c0db5c6..adabf48 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 f352c74..40bad85 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/log/compiler/message.cc b/src/lib/log/compiler/message.cc
index 155aa55..53a24ee 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<string> 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/__init__.py b/src/lib/python/isc/__init__.py
index 9204792..8fcbf42 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 acd2acc..ede3cbf 100644
--- a/src/lib/python/isc/log/Makefile.am
+++ b/src/lib/python/isc/log/Makefile.am
@@ -1,8 +1,18 @@
-SUBDIRS = . tests
+SUBDIRS = tests
-python_PYTHON = __init__.py log.py
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CXXFLAGS = $(B10_CXXFLAGS)
-pythondir = $(pyexecdir)/isc/log
+pythondir = $(pyexecdir)/isc
+python_LTLIBRARIES = log.la
+log_la_SOURCES = log.cc
-pytest:
- $(SHELL) tests/log_test
+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)
+
+# 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
index a34e164..ad77dff 100644
--- a/src/lib/python/isc/log/__init__.py
+++ b/src/lib/python/isc/log/__init__.py
@@ -1 +1,29 @@
-from isc.log.log import *
+# 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/log.cc b/src/lib/python/isc/log/log.cc
new file mode 100644
index 0000000..68cf213
--- /dev/null
+++ b/src/lib/python/isc/log/log.cc
@@ -0,0 +1,629 @@
+// 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 <Python.h>
+#include <structmember.h>
+
+#include <config.h>
+
+#include <log/message_dictionary.h>
+#include <log/logger_manager.h>
+#include <log/logger.h>
+
+#include <string>
+#include <boost/bind.hpp>
+
+using namespace isc::log;
+using std::string;
+using boost::bind;
+
+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);
+
+ try {
+ delete testDictionary;
+ testDictionary = NULL;
+ 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);
+ }
+}
+
+PyObject*
+reset(PyObject*, PyObject*) {
+ 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|siz", &root, &severity, &dbglevel, &file)) {
+ return (NULL);
+ }
+
+ try {
+ LoggerManager::init(root, getSeverity(severity), dbglevel, file);
+ }
+ 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, "
+ "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."},
+ {"reset", reset, METH_NOARGS,
+ "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 "
+ "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}
+};
+
+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);
+}
+
+// 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_getEffectiveDebugLevel(LoggerWrapper* self, PyObject*) {
+ try {
+ return (Py_BuildValue("i", self->logger_->getEffectiveDebugLevel()));
+ }
+ 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;
+}
+
+template<class FPtr> // 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);
+ }
+}
+
+// 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<class Function>
+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 least %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 least 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<PyCFunction>(Logger_getEffectiveSeverity),
+ METH_NOARGS, "Returns the effective logging severity as string" },
+ { "get_effective_debug_level",
+ reinterpret_cast<PyCFunction>(Logger_getEffectiveDebugLevel),
+ METH_NOARGS, "Returns the current debug level." },
+ { "set_severity",
+ reinterpret_cast<PyCFunction>(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."
+ },
+ { "is_debug_enabled", reinterpret_cast<PyCFunction>(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<PyCFunction>(Logger_isInfoEnabled),
+ METH_NOARGS, "Returns if the logger would log info message now." },
+ { "is_warn_enabled", reinterpret_cast<PyCFunction>(Logger_isWarnEnabled),
+ METH_NOARGS, "Returns if the logger would log warn message now." },
+ { "is_error_enabled", reinterpret_cast<PyCFunction>(Logger_isErrorEnabled),
+ METH_NOARGS, "Returns if the logger would log error message now." },
+ { "is_fatal_enabled", reinterpret_cast<PyCFunction>(Logger_isFatalEnabled),
+ METH_NOARGS, "Returns if the logger would log fatal message now." },
+ { "debug", reinterpret_cast<PyCFunction>(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<PyCFunction>(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<PyCFunction>(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<PyCFunction>(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<PyCFunction>(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 }
+};
+
+PyTypeObject logger_type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "isc.log.Logger",
+ sizeof(LoggerWrapper), // tp_basicsize
+ 0, // tp_itemsize
+ reinterpret_cast<destructor>(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<initproc>(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",
+ "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
+};
+
+} // end anonymous namespace
+
+PyMODINIT_FUNC
+PyInit_log(void) {
+ PyObject* mod = PyModule_Create(&iscLog);
+ if (mod == NULL) {
+ return (NULL);
+ }
+
+ if (PyType_Ready(&logger_type) < 0) {
+ return (NULL);
+ }
+
+ if (PyModule_AddObject(mod, "Logger",
+ static_cast<PyObject*>(static_cast<void*>(
+ &logger_type))) < 0) {
+ return (NULL);
+ }
+ Py_INCREF(&logger_type);
+
+ return (mod);
+}
diff --git a/src/lib/python/isc/log/log.py b/src/lib/python/isc/log/log.py
deleted file mode 100644
index 74261e2..0000000
--- 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 86b3e5d..f2825cb 100644
--- a/src/lib/python/isc/log/tests/Makefile.am
+++ b/src/lib/python/isc/log/tests/Makefile.am
@@ -1,11 +1,13 @@
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
+ 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/check_output.sh b/src/lib/python/isc/log/tests/check_output.sh
new file mode 100755
index 0000000..32146af
--- /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 0000000..d3c6770
--- /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 0000000..af05f61
--- /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.set_severity("DEBUG", 99)
+logger.debug(1, MSG_ID, 2, 3)
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 60e5e3f..0000000
--- 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:- at 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
index 026dee1..a463d59 100644
--- a/src/lib/python/isc/log/tests/log_test.py
+++ b/src/lib/python/isc/log/tests/log_test.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2010 Internet Systems Consortium.
+# 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
@@ -13,225 +13,121 @@
# 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 *
+# This tests it can be loaded, nothing more yet
+import isc.log
import unittest
-import os
-import sys
-import tempfile
-
-
-class TestRotateFileHandler(unittest.TestCase):
+class LogDict(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()
-
+ # We work on a test dictionary now.
+ isc.log.set_test_dictionary(True)
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")
+ # Return to the global dictionary
+ isc.log.set_test_dictionary(False)
- def test_encodeLevel(self):
- sysLevel = self.handler._encodeLevel(logging.ERROR)
- self.assertEqual(sysLevel, syslog.LOG_ERR)
+ 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)
- def test_emit(self):
- syslog_message = "bind10 syslog testing"
- record = logging.LogRecord(None, None, "", 0, syslog_message, (), None, None)
- self.handler.emit(record)
+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", "DEBUG", 50, None)
+
+ 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", "INFO", 0, "/no/such/file");
+
+class Logger(unittest.TestCase):
+ def tearDown(self):
+ isc.log.reset()
-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
+ isc.log.init("root", "DEBUG", 50)
+ self.sevs = ['INFO', 'WARN', 'ERROR', 'FATAL']
+
+ # Checks defaults of the logger
+ def defaults(self, logger):
+ self.assertEqual(logger.get_effective_severity(), "DEBUG")
+ self.assertEqual(logger.get_effective_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_effective_debug_level(), 25)
+ for sev in self.sevs:
+ logger.set_severity(sev)
+ self.assertEqual(logger.get_effective_severity(), sev)
+ self.assertEqual(logger.get_effective_debug_level(), 0)
+ # Return to default
+ logger.set_severity(None)
+ 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))
+
+ 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()
More information about the bind10-changes
mailing list