aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'cvs2svn_lib/log.py')
-rw-r--r--cvs2svn_lib/log.py174
1 files changed, 174 insertions, 0 deletions
diff --git a/cvs2svn_lib/log.py b/cvs2svn_lib/log.py
new file mode 100644
index 0000000..798350c
--- /dev/null
+++ b/cvs2svn_lib/log.py
@@ -0,0 +1,174 @@
+# (Be in -*- python -*- mode.)
+#
+# ====================================================================
+# Copyright (c) 2000-2008 CollabNet. All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://subversion.tigris.org/license-1.html.
+# If newer versions of this license are posted there, you may use a
+# newer version instead, at your option.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For exact contribution history, see the revision
+# history and logs, available at http://cvs2svn.tigris.org/.
+# ====================================================================
+
+"""This module contains a simple logging facility for cvs2svn."""
+
+
+import sys
+import time
+import threading
+
+
+class Log:
+ """A Simple logging facility.
+
+ If self.log_level is DEBUG or higher, each line will be timestamped
+ with the number of wall-clock seconds since the time when this
+ module was first imported.
+
+ If self.use_timestamps is True, each line will be timestamped with a
+ human-readable clock time.
+
+ The public methods of this class are thread-safe.
+
+ This class is a Borg; see
+ http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66531."""
+
+ # These constants represent the log levels that this class supports.
+ # The increase_verbosity() and decrease_verbosity() methods rely on
+ # these constants being consecutive integers:
+ ERROR = -2
+ WARN = -1
+ QUIET = 0
+ NORMAL = 1
+ VERBOSE = 2
+ DEBUG = 3
+
+ start_time = time.time()
+
+ __shared_state = {}
+
+ def __init__(self):
+ self.__dict__ = self.__shared_state
+ if self.__dict__:
+ return
+
+ self.log_level = Log.NORMAL
+
+ # Set this to True if you want to see timestamps on each line output.
+ self.use_timestamps = False
+
+ # The output file to use for errors:
+ self._err = sys.stderr
+
+ # The output file to use for lower-priority messages:
+ self._out = sys.stdout
+
+ # Lock to serialize writes to the log:
+ self.lock = threading.Lock()
+
+ def increase_verbosity(self):
+ self.lock.acquire()
+ try:
+ self.log_level = min(self.log_level + 1, Log.DEBUG)
+ finally:
+ self.lock.release()
+
+ def decrease_verbosity(self):
+ self.lock.acquire()
+ try:
+ self.log_level = max(self.log_level - 1, Log.ERROR)
+ finally:
+ self.lock.release()
+
+ def is_on(self, level):
+ """Return True iff messages at the specified LEVEL are currently on.
+
+ LEVEL should be one of the constants Log.WARN, Log.QUIET, etc."""
+
+ return self.log_level >= level
+
+ def _timestamp(self):
+ """Return a timestamp if needed, as a string with a trailing space."""
+
+ retval = []
+
+ if self.log_level >= Log.DEBUG:
+ retval.append('%f: ' % (time.time() - self.start_time,))
+
+ if self.use_timestamps:
+ retval.append(time.strftime('[%Y-%m-%d %I:%M:%S %Z] - '))
+
+ return ''.join(retval)
+
+ def _write(self, out, *args):
+ """Write a message to OUT.
+
+ If there are multiple ARGS, they will be separated by spaces. If
+ there are multiple lines, they will be output one by one with the
+ same timestamp prefix."""
+
+ timestamp = self._timestamp()
+ s = ' '.join(map(str, args))
+ lines = s.split('\n')
+ if lines and not lines[-1]:
+ del lines[-1]
+
+ self.lock.acquire()
+ try:
+ for s in lines:
+ out.write('%s%s\n' % (timestamp, s,))
+ # Ensure that log output doesn't get out-of-order with respect to
+ # stderr output.
+ out.flush()
+ finally:
+ self.lock.release()
+
+ def write(self, *args):
+ """Write a message to SELF._out.
+
+ This is a public method to use for writing to the output log
+ unconditionally."""
+
+ self._write(self._out, *args)
+
+ def error(self, *args):
+ """Log a message at the ERROR level."""
+
+ if self.is_on(Log.ERROR):
+ self._write(self._err, *args)
+
+ def warn(self, *args):
+ """Log a message at the WARN level."""
+
+ if self.is_on(Log.WARN):
+ self._write(self._out, *args)
+
+ def quiet(self, *args):
+ """Log a message at the QUIET level."""
+
+ if self.is_on(Log.QUIET):
+ self._write(self._out, *args)
+
+ def normal(self, *args):
+ """Log a message at the NORMAL level."""
+
+ if self.is_on(Log.NORMAL):
+ self._write(self._out, *args)
+
+ def verbose(self, *args):
+ """Log a message at the VERBOSE level."""
+
+ if self.is_on(Log.VERBOSE):
+ self._write(self._out, *args)
+
+ def debug(self, *args):
+ """Log a message at the DEBUG level."""
+
+ if self.is_on(Log.DEBUG):
+ self._write(self._out, *args)
+
+