Changeset 471:078b9eb64535
- Timestamp:
- 08/28/08 17:22:48 (4 months ago)
- Files:
-
- ChangeLog (modified) (1 diff)
- doc/logging.xhtml (modified) (1 diff)
- foolscap/logging/incident.py (modified) (3 diffs)
- foolscap/logging/interfaces.py (modified) (1 diff)
- foolscap/logging/log.py (modified) (3 diffs)
- foolscap/test/test_logging.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
ChangeLog
r470 r471 1 1 2008-08-28 Brian Warner <warner@lothar.com> 2 3 * foolscap/logging/log.py (FoolscapLogger.declare_incident): 4 combine overlapping incidents, by passing new triggers to an 5 existing reporter instead of creating a new one. Helps with #85. 6 * foolscap/logging/incident.py (IncidentReporter.new_trigger): new 7 method to add subsequent triggers to an existing reporter. This 8 doesn't do anything yet. It should be improved to record the other 9 triggers in a trailer (since it's too late to add it to the 10 header). Every triggering event will make it into an incident 11 somewhere, but the report-file analysis tools may not know how to 12 pay attention to the subsequent triggers. 13 * foolscap/logging/interfaces.py (IIncidentReporter.new_trigger): same 14 * foolscap/test/test_logging.py (Incidents.test_overlapping): test it 15 * doc/logging.xhtml: mention incident-coalescing 2 16 3 17 * foolscap/logging/log.py: add bridge-foolscap-logs-to-twisted doc/logging.xhtml
r470 r471 480 480 logging code should capture the otherwise-ordinary events performed by this 481 481 recovery code.</p> 482 483 <p>Overlapping incidents will be combined: if an incident reporter is already 484 active when the qualifier sees a new triggering event, that event is just 485 added to the existing reporter.</p> 482 486 483 487 <p>The incident reporter can be overridden as well, by calling foolscap/logging/incident.py
r440 r471 61 61 self.logger = logger 62 62 self.tubid_s = tubid_s 63 self.active = True 64 65 def is_active(self): 66 return self.active 63 67 64 68 def format_time(self, when): … … 106 110 107 111 if self.TRAILING_DELAY is None: 112 self.active = False 108 113 eventually(self.finished_recording) 109 114 else: … … 127 132 self.stop_recording() 128 133 134 def new_trigger(self, ev): 135 # it is too late to add this to the header. We could add it to a 136 # trailer, though. 137 pass 138 129 139 def stop_recording(self): 130 140 self.still_recording = False 141 self.active = False 131 142 if self.timer.active(): 132 143 self.timer.cancel() foolscap/logging/interfaces.py
r464 r471 129 129 def incident_declared(triggering_event): 130 130 """This is called when an Incident needs to be recorded.""" 131 def new_trigger(triggering_event): 132 """This is called when a triggering event occurs while an incident is 133 already being reported. If the event happened later, it would trigger 134 a new incident. Since it overlapped with the existing incident, it 135 will just be added to that incident. 136 137 The triggering event will also be reported through the usual 138 event-publish-subscribe mechanism. This method is provided to give 139 the reporter the opportunity to mark the event somehow, for the 140 benefit of incident-file analysis tools. 141 """ 142 def is_active(): 143 """Returns True if the reporter is still running. While in this 144 state, new Incident triggers will be passed to the existing reporter 145 instead of causing a new Incident to be declared. This will tend to 146 coalesce back-to-back problems into a single Incident.""" 147 foolscap/logging/log.py
r470 r471 54 54 self.active_incident_qualifier = None 55 55 self.incident_reporter_factory = IncidentReporter 56 self.active_incident_reporter s = weakref.WeakKeyDictionary()56 self.active_incident_reporter_weakref = None 57 57 self.incidents_declared = 0 58 58 self.incidents_recorded = 0 … … 250 250 def declare_incident(self, triggering_event): 251 251 self.incidents_declared += 1 252 ir = self.get_active_incident_reporter() 253 if ir: 254 ir.new_trigger(triggering_event) 255 return 252 256 if self.logdir: # just in case 253 257 ir = self.incident_reporter_factory(self.logdir, self, "local") 254 self.active_incident_reporter s[ir] = None255 ir.incident_declared(triggering_event) 258 self.active_incident_reporter_weakref = weakref.ref(ir) 259 ir.incident_declared(triggering_event) # this takes a few seconds 256 260 257 261 def incident_recorded(self, filename, name, trigger): … … 265 269 for o in self._immediate_incident_observers: 266 270 o(name, trigger) 271 272 def get_active_incident_reporter(self): 273 if self.active_incident_reporter_weakref: 274 ir = self.active_incident_reporter_weakref() 275 if ir and ir.is_active(): 276 return ir 277 return None 267 278 268 279 def setLogPort(self, logport): foolscap/test/test_logging.py
r470 r471 229 229 l.msg("3-trigger", level=log.BAD) 230 230 self.failUnlessEqual(l.incidents_declared, 1) 231 self.failUnless Equal(len(l.active_incident_reporters), 1)231 self.failUnless(l.get_active_incident_reporter()) 232 232 # at this point, the uncompressed logfile should be present, and it 233 233 # should contain all the events up to and including the trigger … … 307 307 self.failUnlessEqual(events[-1]["d"]["message"], "6") 308 308 d.addCallback(_check) 309 return d 310 311 def test_overlapping(self): 312 l = log.FoolscapLogger() 313 l.setLogDir("logging/Incidents/overlapping") 314 got_logdir = l.logdir 315 self.failUnlessEqual(got_logdir, 316 os.path.abspath("logging/Incidents/overlapping")) 317 d = defer.Deferred() 318 def _go(name, trigger): 319 d.callback( (name, trigger) ) 320 l.addImmediateIncidentObserver(_go) 321 l.setIncidentReporterFactory(ImpatientReporter) 322 l.msg("1") 323 l.msg("2-trigger", level=log.BAD) 324 self.failUnlessEqual(l.incidents_declared, 1) 325 self.failUnless(l.get_active_incident_reporter()) 326 l.msg("3-trigger", level=log.BAD) 327 self.failUnlessEqual(l.incidents_declared, 2) 328 self.failUnless(l.get_active_incident_reporter()) 329 330 def _check(res): 331 self.failUnlessEqual(l.incidents_recorded, 1) 332 self.failUnlessEqual(len(l.recent_recorded_incidents), 1) 333 # at this point, the logfile should be present, and it should 334 # contain all the events up to and including both triggers 335 336 files = os.listdir(got_logdir) 337 self.failUnlessEqual(len(files), 1) 338 events = self._read_logfile(os.path.join(got_logdir, files[0])) 339 340 self.failUnlessEqual(len(events), 1+3) 341 self.failUnlessEqual(events[0]["header"]["trigger"]["message"], 342 "2-trigger") 343 self.failUnlessEqual(events[1]["d"]["message"], "1") 344 self.failUnlessEqual(events[2]["d"]["message"], "2-trigger") 345 self.failUnlessEqual(events[3]["d"]["message"], "3-trigger") 346 d.addCallback(_check) 347 309 348 return d 310 349
