aboutsummaryrefslogtreecommitdiff
path: root/rpki/log.py
diff options
context:
space:
mode:
Diffstat (limited to 'rpki/log.py')
-rw-r--r--rpki/log.py199
1 files changed, 199 insertions, 0 deletions
diff --git a/rpki/log.py b/rpki/log.py
new file mode 100644
index 00000000..c605331a
--- /dev/null
+++ b/rpki/log.py
@@ -0,0 +1,199 @@
+# $Id$
+#
+# Copyright (C) 2013--2014 Dragon Research Labs ("DRL")
+# Portions copyright (C) 2009--2012 Internet Systems Consortium ("ISC")
+# Portions copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN")
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notices and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND DRL, ISC, AND ARIN DISCLAIM ALL
+# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DRL,
+# ISC, OR ARIN 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.
+
+"""
+Logging facilities for RPKI libraries.
+"""
+
+import syslog
+import sys
+import os
+import time
+import traceback as tb
+
+try:
+ have_setproctitle = False
+ if os.getenv("DISABLE_SETPROCTITLE") is None:
+ import setproctitle
+ have_setproctitle = True
+except ImportError:
+ pass
+
+## @var enable_trace
+# Whether call tracing is enabled.
+
+enable_trace = False
+
+## @var show_python_ids
+# Whether __repr__() methods should show Python id numbers
+
+show_python_ids = False
+
+## @var enable_tracebacks
+# Whether tracebacks are enabled globally. Individual classes and
+# modules may choose to override this.
+
+enable_tracebacks = False
+
+## @var use_setproctitle
+# Whether to use setproctitle (if available) to change name shown for
+# this process in ps listings (etc).
+
+use_setproctitle = True
+
+## @var proctitle_extra
+
+# Extra text to include in proctitle display. By default this is the
+# tail of the current directory name, as this is often useful, but you
+# can set it to something else if you like. If None or the empty
+# string, the extra information field will be omitted from the proctitle.
+
+proctitle_extra = os.path.basename(os.getcwd())
+
+def init(ident = "rpki", flags = syslog.LOG_PID, facility = syslog.LOG_DAEMON, use_syslog = None, log_file = sys.stderr, tag_log_lines = True):
+ """
+ Initialize logging system.
+ """
+
+ # If caller didn't say whether to use syslog, use log file if user supplied one, otherwise use syslog
+
+ if use_syslog is None:
+ use_syslog = log_file is sys.stderr
+
+ logger.use_syslog = use_syslog
+ logger.tag_log_lines = tag_log_lines
+
+ if use_syslog:
+ syslog.openlog(ident, flags, facility)
+
+ else:
+ logger.tag = ident
+ logger.pid = os.getpid()
+ logger.log_file = log_file
+
+ if ident and have_setproctitle and use_setproctitle:
+ if proctitle_extra:
+ setproctitle.setproctitle("%s (%s)" % (ident, proctitle_extra))
+ else:
+ setproctitle.setproctitle(ident)
+
+class logger(object):
+ """
+ Closure for logging.
+ """
+
+ use_syslog = True
+ tag = ""
+ pid = 0
+ log_file = sys.stderr
+
+ def __init__(self, priority):
+ self.priority = priority
+
+ def __call__(self, message):
+ if self.use_syslog:
+ syslog.syslog(self.priority, message)
+ elif self.tag_log_lines:
+ self.log_file.write("%s %s[%d]: %s\n" % (time.strftime("%F %T"), self.tag, self.pid, message))
+ self.log_file.flush()
+ else:
+ self.log_file.write(message + "\n")
+ self.log_file.flush()
+
+error = logger(syslog.LOG_ERR)
+warn = logger(syslog.LOG_WARNING)
+note = logger(syslog.LOG_NOTICE)
+info = logger(syslog.LOG_INFO)
+debug = logger(syslog.LOG_DEBUG)
+
+
+def set_trace(enable):
+ """
+ Enable or disable call tracing.
+ """
+
+ global enable_trace
+ enable_trace = enable
+
+def trace():
+ """
+ Execution trace -- where are we now, and whence came we here?
+ """
+
+ if enable_trace:
+ bt = tb.extract_stack(limit = 3)
+ return debug("[%s() at %s:%d from %s:%d]" % (bt[1][2], bt[1][0], bt[1][1], bt[0][0], bt[0][1]))
+
+def traceback(do_it = None):
+ """
+ Consolidated backtrace facility with a bit of extra info. Argument
+ specifies whether or not to log the traceback (some modules and
+ classes have their own controls for this, this lets us provide a
+ unified interface). If no argument is specified, we use the global
+ default value rpki.log.enable_tracebacks.
+
+ Assertion failures generate backtraces unconditionally, on the
+ theory that (a) assertion failures are programming errors by
+ definition, and (b) it's often hard to figure out what's triggering
+ a particular assertion failure without the backtrace.
+ """
+
+ if do_it is None:
+ do_it = enable_tracebacks
+
+ e = sys.exc_info()[1]
+ assert e is not None, "rpki.log.traceback() called without valid trace on stack! This should not happen."
+
+ if do_it or isinstance(e, AssertionError):
+ bt = tb.extract_stack(limit = 3)
+ error("Exception caught in %s() at %s:%d called from %s:%d" % (bt[1][2], bt[1][0], bt[1][1], bt[0][0], bt[0][1]))
+ bt = tb.format_exc()
+ assert bt is not None, "Apparently I'm still not using the right test for null backtrace"
+ for line in bt.splitlines():
+ warn(line)
+
+def log_repr(obj, *tokens):
+ """
+ Constructor for __repr__() strings, handles suppression of Python
+ IDs as needed, includes self_handle when available.
+ """
+
+ # pylint: disable=W0702
+
+ words = ["%s.%s" % (obj.__class__.__module__, obj.__class__.__name__)]
+ try:
+ words.append("{%s}" % obj.self.self_handle)
+ except:
+ pass
+
+ for token in tokens:
+ if token is not None:
+ try:
+ s = str(token)
+ except:
+ s = "???"
+ debug("Failed to generate repr() string for object of type %r" % type(token))
+ traceback()
+ if s:
+ words.append(s)
+
+ if show_python_ids:
+ words.append(" at %#x" % id(obj))
+
+ return "<" + " ".join(words) + ">"