Provide an already-constructed instance of Log.
[cvs2svn.git] / cvs2svn_lib / log.py
bloba5dc67dc2d207f38c37f65104744802384f93f70
1 # (Be in -*- python -*- mode.)
3 # ====================================================================
4 # Copyright (c) 2000-2008 CollabNet. All rights reserved.
6 # This software is licensed as described in the file COPYING, which
7 # you should have received as part of this distribution. The terms
8 # are also available at http://subversion.tigris.org/license-1.html.
9 # If newer versions of this license are posted there, you may use a
10 # newer version instead, at your option.
12 # This software consists of voluntary contributions made by many
13 # individuals. For exact contribution history, see the revision
14 # history and logs, available at http://cvs2svn.tigris.org/.
15 # ====================================================================
17 """This module contains a simple logging facility for cvs2svn."""
20 import sys
21 import time
22 import threading
25 class Log:
26 """A Simple logging facility.
28 If self.log_level is DEBUG or higher, each line will be timestamped
29 with the number of wall-clock seconds since the time when this
30 module was first imported.
32 The public methods of this class are thread-safe.
34 This class is a Borg; see
35 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66531."""
37 # These constants represent the log levels that this class supports.
38 # The increase_verbosity() and decrease_verbosity() methods rely on
39 # these constants being consecutive integers:
40 ERROR = -2
41 WARN = -1
42 QUIET = 0
43 NORMAL = 1
44 VERBOSE = 2
45 DEBUG = 3
47 start_time = time.time()
49 __shared_state = {}
51 def __init__(self):
52 self.__dict__ = self.__shared_state
53 if self.__dict__:
54 return
56 self.log_level = Log.NORMAL
58 # The output file to use for errors:
59 self._err = sys.stderr
61 # The output file to use for lower-priority messages:
62 self._out = sys.stdout
64 # Lock to serialize writes to the log:
65 self.lock = threading.Lock()
67 def increase_verbosity(self):
68 self.lock.acquire()
69 try:
70 self.log_level = min(self.log_level + 1, Log.DEBUG)
71 finally:
72 self.lock.release()
74 def decrease_verbosity(self):
75 self.lock.acquire()
76 try:
77 self.log_level = max(self.log_level - 1, Log.ERROR)
78 finally:
79 self.lock.release()
81 def is_on(self, level):
82 """Return True iff messages at the specified LEVEL are currently on.
84 LEVEL should be one of the constants Log.WARN, Log.QUIET, etc."""
86 return self.log_level >= level
88 def _timestamp(self):
89 """Return a timestamp if needed, as a string with a trailing space."""
91 retval = []
93 if self.log_level >= Log.DEBUG:
94 retval.append('%f: ' % (time.time() - self.start_time,))
96 return ''.join(retval)
98 def _write(self, out, *args):
99 """Write a message to OUT.
101 If there are multiple ARGS, they will be separated by spaces. If
102 there are multiple lines, they will be output one by one with the
103 same timestamp prefix."""
105 timestamp = self._timestamp()
106 s = ' '.join(map(str, args))
107 lines = s.split('\n')
108 if lines and not lines[-1]:
109 del lines[-1]
111 self.lock.acquire()
112 try:
113 for s in lines:
114 out.write('%s%s\n' % (timestamp, s,))
115 # Ensure that log output doesn't get out-of-order with respect to
116 # stderr output.
117 out.flush()
118 finally:
119 self.lock.release()
121 def write(self, *args):
122 """Write a message to SELF._out.
124 This is a public method to use for writing to the output log
125 unconditionally."""
127 self._write(self._out, *args)
129 def error(self, *args):
130 """Log a message at the ERROR level."""
132 if self.is_on(Log.ERROR):
133 self._write(self._err, *args)
135 def warn(self, *args):
136 """Log a message at the WARN level."""
138 if self.is_on(Log.WARN):
139 self._write(self._out, *args)
141 def quiet(self, *args):
142 """Log a message at the QUIET level."""
144 if self.is_on(Log.QUIET):
145 self._write(self._out, *args)
147 def normal(self, *args):
148 """Log a message at the NORMAL level."""
150 if self.is_on(Log.NORMAL):
151 self._write(self._out, *args)
153 def verbose(self, *args):
154 """Log a message at the VERBOSE level."""
156 if self.is_on(Log.VERBOSE):
157 self._write(self._out, *args)
159 def debug(self, *args):
160 """Log a message at the DEBUG level."""
162 if self.is_on(Log.DEBUG):
163 self._write(self._out, *args)
166 # Create an instance that everybody can use:
167 logger = Log()