1
2 """
3 Asychronous execution monitoring service.
4
5 Long running computations need to convey status information to the user.
6 This status can take multiple forms, such as output to the console or
7 activity on a GUI, or even mail to your inbox.
8
9 `park.core.message` defines several standard messages::
10
11 `Started` for job start
12 `Joined` first message when joining an already running job
13 `Progress` for job activity
14 `Improved` for partial results
15 `Completed` for final result
16 `Aborted` when job is killed
17 `Error` when job has an error
18 `Log` for various debugging messages
19
20 The `Monitor` class handles the stream of messages, dispatching each
21 to a user defined handler. For each message, Monitor.put(message)
22 will look for the method named onMonitorName where Name is the name
23 of the message class. For example, onMonitorStarted(self, message)
24 will be called in response to the Started message. If onMonitorName
25 is not defined, then onMonitorMessage will be called. The default
26 behaviour of onMonitorMessage is to print the message on the console.
27
28 Individual services may have specialized message types. Such services
29 may also provide a specialized Monitor subclass to handle these
30 messages.
31
32 Log messages are sent to the standard system logger using onMonitorLog.
33 See logging in the python standard library for details on controlling
34 the logger.
35
36 `park.core.wxmonitor.Monitor` is a predefined monitor which
37 dispatches events to a wx GUI.
38 """
39 __all__ = ['Monitor']
40
41 import sys
42 import logging
45 """
46 Messages that are received during the processing of the job.
47
48 Standard message types::
49
50 `Started`, `Progress`, `Improved`, `Completed`,
51 `Error`, `Aborted`, `Log`
52
53 Specific job types may have their own monitor messages.
54
55 The messages themselves should all produce nicely formatted results
56 in response to str(message).
57
58 The message dispatch calls on<Class>(message) if the on<Class>
59 method exists for the message type. If not, then dispatch
60 calls otherwise(message). By default onLog(message) submits the
61 log record to the logger.
62
63 Subclass Monitor to define your own behaviours.
64 """
65 - def put(self, message):
66 """
67 Called from thread when new message has arrived.
68 """
69 method = "onMonitor"+message.__class__.__name__
70 fn = getattr(self, method, self.onMonitorMessage)
71 fn(message)
72
74 """
75 What to do if the message handler is not found.
76
77 Default is to ignore the message.
78 """
79 print ">",str(message)
80
82 """
83 Called when the job sends a logging record.
84
85 The logging record contains a normal python logging record.
86
87 The default behaviour is to tie into the application logging
88 system using::
89
90 logger = logging.getLogger(message.record.name)
91 logger.handle(message.record)
92
93 Logging levels are set in the job controller.
94 """
95 logging.basicConfig()
96 logger = logging.getLogger(message.record.name)
97 logger.handle(message.record)
98
99
100
101 from park.util.threads import threaded
104 import sys, time
105 import park.core.message as msg
106
107 def messagestream(monitor,rate,stream):
108 for m in stream:
109 time.sleep(rate)
110 monitor.put(m)
111 time.sleep(rate)
112 R = logging.LogRecord('hi',60,'hello.py',3,'log message',(),None,'here')
113 try: raise Exception('Test exception')
114 except: trace = sys.exc_info()
115 stream=[msg.Started(),
116 msg.Improved(status='Good'),
117 msg.Progress(1,10),
118 msg.Progress(2,10),
119 msg.Progress(3,10),
120 msg.Joined(progress=(3,10),improved='Good'),
121 msg.Improved(status='Better!'),
122 msg.Aborted(),
123 msg.Started(),
124 msg.Progress(1,10,'seconds'),
125 msg.Improved(status='Better!'),
126 msg.Progress(8,10),
127 msg.Completed(status='Best!'),
128 msg.Started(),
129 msg.Log(R),
130 msg.Progress(6,10),
131 msg.Error(trace),
132 msg.Completed(status='Bye!')]
133 messagestream(monitor,rate,stream)
134
138
140 class TestMonitor(Monitor):
141 def __init__(self): self.id = 0
142 def onMonitorStarted(self, msg):
143 assert self.id in [0,8,13]
144 self.id+=1
145 def onMonitorImproved(self, msg):
146 assert self.id in [1,6,10]
147 self.id+=1
148 def onMonitorProgress(self, msg):
149 assert self.id in [2,3,4,9,11,15]
150 self.id+=1
151
152
153
154 def onMonitorAborted(self, msg):
155 assert self.id in [7]
156 self.id += 1
157 def onMonitorCompleted(self, msg):
158 assert self.id in [12]
159 self.id += 1
160 def onMonitorLog(self, msg):
161 assert self.id in [14]
162 self.id += 1
163 def onMonitorError(self, msg):
164 assert self.id in [16]
165 self.id += 1
166 def onMonitorMessage(self, msg):
167
168
169 assert msg.__class__.__name__ == 'Joined'
170 assert self.id in [5]
171 self.id += 1
172 _demo_stream(rate=0, monitor=TestMonitor())
173
174 if __name__ == "__main__":
175
176 test()
177