source: sasview/park-1.2.1/park/monitor.py @ 500be82

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 500be82 was 3570545, checked in by Mathieu Doucet <doucetm@…>, 13 years ago

Adding park Part 2

  • Property mode set to 100644
File size: 7.6 KB
Line 
1# This program is public domain
2"""
3Asychronous execution monitoring service.
4
5Long running computations need to convey status information to the user.
6This status can take multiple forms, such as output to the console or
7activity on a GUI, or even mail to your inbox.
8
9park.monitor defines several standard message types::
10
11    `Start` for job start
12    `Join` first message when joining an already running job
13    `Progress` for job activity
14    `Improvement` for partial results
15    `Complete` for final result
16    `Abort` when job is killed
17    `Error` when job has an error
18    `Log` for various debugging messages
19
20Individual services may have specialized message types.
21
22park.monitor also defines `Monitor` to process the various kinds of messages,
23and dispatch them to the various user defined handlers.
24
25For each message type, the Monitor dispatcher will look for a function
26named onMonitorQQQ where QQQ is the message type.  For example,
27onMonitorStart(self, message) will be called in response to a Start message.
28If onMonitorQQQ is not defined, then onMonitorMessage will be called.  The
29default behaviour of onMonitorMessage is to print the message on the console.
30
31Log messages are sent to the standard system logger.  See logging in the
32python standard library for details.
33
34The Monitor class has methods for onMonitorStart(message), etc.
35In panel, be sure to have methods for onMonitorStart(message),
36onMonitorProgress(message), etc., for the kinds of monitor messages
37the application will send.  The catch-all method is onMonitorMessage.
38
39See `park.monitor` for details on the message types.  Individual services
40may have additional message types.
41
42"""
43__all__ = ['Monitor']
44
45import sys
46import logging
47import traceback
48
49class Message(object):
50    """
51    Message type
52    """
53
54class Start(Message):
55    """
56    Start.
57
58    Sent when the job has started processing.
59    """
60    def __str__(self): return "Start"
61
62class Join(Message):
63    """
64    Join: k units of n with partial result
65   
66    Sent when the listener is attached to a running job.  This is
67    a combination of Progress and Improvement.
68    """
69    def __init__(self, k, n, partial):
70        self.total = n
71        """Total work to complete"""
72        self.complete = k
73        """Amount of work complete"""
74        self.result = partial
75        """The partial result completed; this is job specific"""
76    def __str__(self): return "Join: "+str(self.result)
77   
78class Progress(Message):
79    """
80    Progress: k units of n.
81
82    Sent when a certain amount of progress has happened.
83
84    Use the job controller to specify the reporting
85    frequency (time and/or percentage).
86    """
87    def __init__(self, k, n, units=None):
88        self.total = n
89        """Total work to complete"""
90        self.complete = k
91        """Amount of work complete"""
92        self.units = units
93        """Units of work, or None"""
94    def __str__(self):
95        if self.units is not None:
96            return "Progress: %s %s of %s"%(self.complete, self.units, self.total)
97        else:
98            return "Progress: %s of %s"%(self.complete, self.total)
99
100class Improvement(Message):
101    """
102    Improvement: partial result.
103
104    Use the job controller to specify the improvement frequency
105    (time and/or percentage).
106    """
107    def __init__(self, partial):
108        self.result = partial
109        """The partial result completed; this is job specific"""
110    def __str__(self):
111        return "Improvement: "+str(self.result)
112
113class Complete(Message):
114    """
115    Complete: final result.
116    """
117    def __init__(self, final):
118        self.result = final
119        """The final completed result; this is job specific"""
120    def __str__(self):
121        return "Complete: "+str(self.result)
122
123class Error(Message):
124    """
125    Traceback stack trace.
126    """
127    def __init__(self, trace=None):
128        if trace == None: trace = sys.exc_info()
129        self.trace = trace
130        """The stack trace returned from exc_info()"""
131    def __str__(self):
132        #print "traceback",traceback.format_exception(*self.trace)
133        try:
134            return "".join(traceback.format_exception(*self.trace))
135        except TypeError:
136            return "Error: "+str(self.trace)
137
138class Abort(Message):
139    """
140    Abort: partial result
141
142    Use the job controller to signal an abort.
143    """
144    def __init__(self, partial):
145        self.result = partial
146        """The partial result completed; this is job specific"""
147    def __str__(self):
148        return "Abort: "+str(self.result)
149
150class Log(Message):
151    """
152    Log module.function: log record
153    """
154    formatter = logging.Formatter("Log %(module)s.%(funcName)s: %(message)s")
155    def __init__(self, record):
156        self.record = record
157        """The partial result completed; this is job specific"""
158    def __str__(self):
159        return self.formatter.format(self.record)
160
161class Monitor(object):
162    """
163    Messages that are received during the processing of the job.
164
165    Standard message types::
166
167        `Start`, `Progress`, `Improvement`, `Complete`, `Error`, `Abort`, `Log`
168
169    Specific job types may have their own monitor messages.
170
171    The messages themselves should all produce nicely formatted results
172    in response to str(message).
173
174    The message dispatch calls on<Class>(message) if the on<Class>
175    method exists for the message type.  If not, then dispatch
176    calls otherwise(message).  By default onLog(message) submits the
177    log record to the logger.
178
179    Subclass Monitor to define your own behaviours.
180    """
181    def put(self, message):
182        """
183        Called from thread when new message has arrived.
184        """
185        fn = getattr(self, 
186                     "onMonitor"+message.__class__.__name__, 
187                     self.onMonitorMessage)
188        fn(message)
189
190    def onMonitorMessage(self, message):
191        """
192        What to do if the message handler is not found.
193
194        Default is to ignore the message.
195        """
196        print ">",str(message)
197
198    def onMonitorLog(self, message):
199        """
200        Called when the job sends a logging record.
201
202        The logging record contains a normal python logging record.
203
204        The default behaviour is to tie into the application logging
205        system using::
206
207            logger = logging.getLogger(message.record.name)
208            logger.handle(message.record)
209
210        Logging levels are set in the job controller.
211        """
212        logging.basicConfig()
213        logger = logging.getLogger(message.record.name)
214        logger.handle(message.record)
215
216
217def demo(rate=0):
218    import sys, time, thread, logging
219    import park.monitor
220
221    monitor = Monitor()
222    def messagestream(monitor,rate,stream):
223        for m in stream:
224            time.sleep(rate)
225            monitor.put(m)
226        time.sleep(rate)
227    R = logging.LogRecord('hi',60,'hello.py',3,'log message',(),None,'here')
228    try: raise Exception('Test exception')
229    except: trace = sys.exc_info()
230    stream=[park.monitor.Start(),
231            park.monitor.Progress(1,10),
232            park.monitor.Progress(2,10),
233            park.monitor.Progress(3,10),
234            park.monitor.Join('Good'),
235            park.monitor.Improvement('Better!'),
236            park.monitor.Abort('Abandoned'),
237            park.monitor.Start(),
238            park.monitor.Progress(1,10,'seconds'),
239            park.monitor.Improvement('Better!'),
240            park.monitor.Progress(8,10),
241            park.monitor.Complete('Best!'),
242            park.monitor.Start(),
243            park.monitor.Log(R),
244            park.monitor.Progress(6,10),
245            park.monitor.Error(trace)]
246    thread.start_new_thread(messagestream, (monitor,rate,stream))
247
248    time.sleep(20*(rate+0.01))
249
250if __name__ == "__main__": demo(rate=0.1)
Note: See TracBrowser for help on using the repository browser.