blob: e6fae6839ea4952c8e49bc55dce35e49910c9efb [file] [log] [blame]
Tor Norbye3a2425a2013-11-04 10:16:08 -08001# epydoc -- Logging
2#
3# Copyright (C) 2005 Edward Loper
4# Author: Edward Loper <edloper@loper.org>
5# URL: <http://epydoc.sf.net>
6#
7# $Id: log.py 1488 2007-02-14 00:34:27Z edloper $
8
9"""
10Functions used to report messages and progress updates to the user.
11These functions are delegated to zero or more registered L{Logger}
12objects, which are responsible for actually presenting the information
13to the user. Different interfaces are free to create and register
14their own C{Logger}s, allowing them to present this information in the
15manner that is best suited to each interface.
16
17@note: I considered using the standard C{logging} package to provide
18this functionality. However, I found that it would be too difficult
19to get that package to provide the behavior I want (esp. with respect
20to progress displays; but also with respect to message blocks).
21
22@group Message Severity Levels: DEBUG, INFO, WARNING, ERROR, FATAL
23"""
24__docformat__ = 'epytext en'
25
26import sys, os
27
28DEBUG = 10
29INFO = 20
30DOCSTRING_WARNING = 25
31WARNING = 30
32ERROR = 40
33FATAL = 40
34
35######################################################################
36# Logger Base Class
37######################################################################
38class Logger:
39 """
40 An abstract base class that defines the interface for X{loggers},
41 which are used by epydoc to report information back to the user.
42 Loggers are responsible for tracking two types of information:
43
44 - Messages, such as warnings and errors.
45 - Progress on the current task.
46
47 This abstract class allows the command-line interface and the
48 graphical interface to each present this information to the user
49 in the way that's most natural for each interface. To set up a
50 logger, create a subclass of C{Logger} that overrides all methods,
51 and register it using L{register_logger}.
52 """
53 #////////////////////////////////////////////////////////////
54 # Messages
55 #////////////////////////////////////////////////////////////
56
57 def log(self, level, message):
58 """
59 Display a message.
60
61 @param message: The message string to display. C{message} may
62 contain newlines, but does not need to end in a newline.
63 @param level: An integer value indicating the severity of the
64 message.
65 """
66
67 def close(self):
68 """
69 Perform any tasks needed to close this logger.
70 """
71
72 #////////////////////////////////////////////////////////////
73 # Message blocks
74 #////////////////////////////////////////////////////////////
75
76 def start_block(self, header):
77 """
78 Start a new message block. Any calls to L{info()},
79 L{warning()}, or L{error()} that occur between a call to
80 C{start_block} and a corresponding call to C{end_block} will
81 be grouped together, and displayed with a common header.
82 C{start_block} can be called multiple times (to form nested
83 blocks), but every call to C{start_block} I{must} be balanced
84 by a call to C{end_block}.
85 """
86
87 def end_block(self):
88 """
89 End a warning block. See L{start_block} for details.
90 """
91
92 #////////////////////////////////////////////////////////////
93 # Progress bar
94 #////////////////////////////////////////////////////////////
95
96 def start_progress(self, header=None):
97 """
98 Begin displaying progress for a new task. C{header} is a
99 description of the task for which progress is being reported.
100 Each call to C{start_progress} must be followed by a call to
101 C{end_progress} (with no intervening calls to
102 C{start_progress}).
103 """
104
105 def end_progress(self):
106 """
107 Finish off the display of progress for the current task. See
108 L{start_progress} for more information.
109 """
110
111 def progress(self, percent, message=''):
112 """
113 Update the progress display.
114
115 @param percent: A float from 0.0 to 1.0, indicating how much
116 progress has been made.
117 @param message: A message indicating the most recent action
118 that contributed towards that progress.
119 """
120
121class SimpleLogger(Logger):
122 def __init__(self, threshold=WARNING):
123 self.threshold = threshold
124 def log(self, level, message):
125 if level >= self.threshold: print message
126
127######################################################################
128# Logger Registry
129######################################################################
130
131_loggers = []
132"""
133The list of registered logging functions.
134"""
135
136def register_logger(logger):
137 """
138 Register a logger. Each call to one of the logging functions
139 defined by this module will be delegated to each registered
140 logger.
141 """
142 _loggers.append(logger)
143
144def remove_logger(logger):
145 _loggers.remove(logger)
146
147######################################################################
148# Logging Functions
149######################################################################
150# The following methods all just delegate to the corresponding
151# methods in the Logger class (above) for each registered logger.
152
153def fatal(*messages):
154 """Display the given fatal message."""
155 message = ' '.join(['%s' % (m,) for m in messages])
156 for logger in _loggers: logger.log(FATAL, message)
157
158def error(*messages):
159 """Display the given error message."""
160 message = ' '.join(['%s' % (m,) for m in messages])
161 for logger in _loggers: logger.log(ERROR, message)
162
163def warning(*messages):
164 """Display the given warning message."""
165 message = ' '.join(['%s' % (m,) for m in messages])
166 for logger in _loggers: logger.log(WARNING, message)
167
168def docstring_warning(*messages):
169 """Display the given docstring warning message."""
170 message = ' '.join(['%s' % (m,) for m in messages])
171 for logger in _loggers: logger.log(DOCSTRING_WARNING, message)
172
173def info(*messages):
174 """Display the given informational message."""
175 message = ' '.join(['%s' % (m,) for m in messages])
176 for logger in _loggers: logger.log(INFO, message)
177
178def debug(*messages):
179 """Display the given debugging message."""
180 message = ' '.join(['%s' % (m,) for m in messages])
181 for logger in _loggers: logger.log(DEBUG, message)
182
183def start_block(header):
184 for logger in _loggers: logger.start_block(header)
185start_block.__doc__ = Logger.start_block.__doc__
186
187def end_block():
188 for logger in _loggers: logger.end_block()
189end_block.__doc__ = Logger.end_block.__doc__
190
191def start_progress(header=None):
192 for logger in _loggers: logger.start_progress(header)
193start_progress.__doc__ = Logger.start_progress.__doc__
194
195def end_progress():
196 for logger in _loggers: logger.end_progress()
197end_progress.__doc__ = Logger.end_progress.__doc__
198
199def progress(percent, message=''):
200 for logger in _loggers: logger.progress(percent, '%s' % message)
201progress.__doc__ = Logger.progress.__doc__
202
203def close():
204 for logger in _loggers: logger.close()