Changeset 493:b79718df78d5
- Timestamp:
- 10/14/08 12:54:35
(3 months ago)
- Author:
- Brian Warner <warner@allmydata.com>
- branch:
- default
- Message:
incident-gatherer: load all 'classify_*.py' files as classifier plugins
-
Files:
-
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
| r492 |
r493 |
|
| | 1 | 2008-10-14 Brian Warner <warner@allmydata.com> |
|---|
| | 2 | |
|---|
| | 3 | * foolscap/logging/gatherer.py |
|---|
| | 4 | (IncidentGathererService.add_classify_files): make the incident |
|---|
| | 5 | gatherer look in its base directory for "classify_*.py" files, use |
|---|
| | 6 | them as plugins with classification functions. |
|---|
| | 7 | (INCIDENT_GATHERER_TACFILE): update example text to match |
|---|
| | 8 | * foolscap/test/test_logging.py (IncidentGatherer): test it |
|---|
| | 9 | (Gatherer.test_wrongdir): exercise another error case |
|---|
| | 10 | * doc/logging.xhtml (gatherer): document it |
|---|
| | 11 | |
|---|
| 1 | 12 | 2008-10-13 Brian Warner <warner@allmydata.com> |
|---|
| 2 | 13 | |
|---|
| r471 |
r493 |
|
| 891 | 891 | <p>The Incident Gatherer uses a collection of user-supplied classification |
|---|
| 892 | 892 | functions to analyze each Incident and place it into one or more categories. |
|---|
| 893 | | To add a classification function, you will need to modify the |
|---|
| 894 | | <code>gatherer.tac</code> file, and make a call to |
|---|
| 895 | | <code>ig.add_classifier()</code> with your function. These functions accept a |
|---|
| 896 | | triggering event and a pathname (from which preceding log events can be |
|---|
| 897 | | extracted, if desired), and should return a list of categories. Each incident |
|---|
| 898 | | can wind up in multiple categories. If no function finds a category for the |
|---|
| 899 | | incident, it will be added to the "unknown" category. All incidents are added |
|---|
| 900 | | to the "all" category.</p> |
|---|
| | 893 | To add a classification function, create a file with a name like |
|---|
| | 894 | "<code>classify_*.py</code>" (such as <code>classify_foolscap.py</code> or |
|---|
| | 895 | <code>classify_db.py</code>), and define a function in it named |
|---|
| | 896 | "<code>classify_incident()</code>". Place this file in the gatherer's |
|---|
| | 897 | directory. All such files will be loaded and evaluated when the gatherer |
|---|
| | 898 | starts.</p> |
|---|
| | 899 | |
|---|
| | 900 | <p>The <code>classify_incident()</code> function will accept a triggering |
|---|
| | 901 | event and a pathname (from which preceding log events can be extracted, if |
|---|
| | 902 | desired), and should return a list of categories. Each incident can wind up |
|---|
| | 903 | in multiple categories. If no function finds a category for the incident, it |
|---|
| | 904 | will be added to the "unknown" category. All incidents are added to the "all" |
|---|
| | 905 | category.</p> |
|---|
| 901 | 906 | |
|---|
| 902 | 907 | <p>The <code>classified/</code> directory will contain a file for each |
|---|
| r480 |
r493 |
|
| 426 | 426 | |
|---|
| 427 | 427 | def add_classifier(self, f): |
|---|
| | 428 | # there are old .tac files that call this explicitly |
|---|
| 428 | 429 | self.classifiers.append(f) |
|---|
| 429 | 430 | |
|---|
| … | … | |
| 436 | 437 | if not os.path.isdir(outputdir): |
|---|
| 437 | 438 | os.makedirs(outputdir) |
|---|
| | 439 | self.add_classify_files() |
|---|
| 438 | 440 | self.classify_stored_incidents(indir) |
|---|
| 439 | 441 | GatheringBase.startService(self) |
|---|
| | 442 | |
|---|
| | 443 | def add_classify_files(self): |
|---|
| | 444 | for fn in os.listdir(self.basedir): |
|---|
| | 445 | if not (fn.startswith("classify_") and fn.endswith(".py")): |
|---|
| | 446 | continue |
|---|
| | 447 | f = open(os.path.join(self.basedir, fn), "r") |
|---|
| | 448 | localdict = {} |
|---|
| | 449 | exec f in localdict |
|---|
| | 450 | self.add_classifier(localdict["classify_incident"]) |
|---|
| 440 | 451 | |
|---|
| 441 | 452 | def classify_stored_incidents(self, indir): |
|---|
| … | … | |
| 535 | 546 | gs = gatherer.IncidentGathererService() |
|---|
| 536 | 547 | |
|---|
| 537 | | # To add a classifier function, call gs.add_classifier(f) like this: |
|---|
| | 548 | # To add a classifier function, store it in a neighboring file named |
|---|
| | 549 | # classify_*.py, in a function named classify_incident(). All such files will |
|---|
| | 550 | # be loaded at startup: |
|---|
| 538 | 551 | # |
|---|
| 539 | | #import re |
|---|
| 540 | | #TUBCON_RE = re.compile(r'^Tub.connectorFinished: WEIRD, <foolscap.negotiate.TubConnector instance at \w+> is not in \[') |
|---|
| 541 | | #def is_foolscap(nodeid_s, incident): |
|---|
| 542 | | # (header, events) = incident |
|---|
| 543 | | # trigger = header['trigger'] |
|---|
| 544 | | # m = trigger.get('message', '') |
|---|
| 545 | | # if TUBCON_RE.search(m): |
|---|
| 546 | | # return 'foolscap-tubconnector' |
|---|
| 547 | | #gs.add_classifier(is_foolscap) |
|---|
| | 552 | # %% cat classify_foolscap.py |
|---|
| | 553 | # import re |
|---|
| | 554 | # TUBCON_RE = re.compile(r'^Tub.connectorFinished: WEIRD, <foolscap.negotiate.TubConnector instance at \w+> is not in \[') |
|---|
| | 555 | # def classify_incident(nodeid_s, incident): |
|---|
| | 556 | # # match some foolscap messages |
|---|
| | 557 | # (header, events) = incident |
|---|
| | 558 | # trigger = header['trigger'] |
|---|
| | 559 | # m = trigger.get('message', '') |
|---|
| | 560 | # if TUBCON_RE.search(m): |
|---|
| | 561 | # return 'foolscap-tubconnector' |
|---|
| | 562 | # %% |
|---|
| 548 | 563 | |
|---|
| 549 | 564 | application = service.Application('incident_gatherer') |
|---|
| r480 |
r493 |
|
| 1023 | 1023 | self.remove_classified_incidents(ig) |
|---|
| 1024 | 1024 | ig2 = self.create_incident_gatherer(basedir, [classify_boom]) |
|---|
| 1025 | | ig2.add_classifier(classify_foom) |
|---|
| | 1025 | ##ig2.add_classifier(classify_foom) |
|---|
| | 1026 | # we add classify_foom by writing it into a file, to exercise the |
|---|
| | 1027 | # look-for-classifier-files code |
|---|
| | 1028 | foomfile = os.path.join(ig2.basedir, "classify_foom.py") |
|---|
| | 1029 | f = open(foomfile, "w") |
|---|
| | 1030 | f.write(''' |
|---|
| | 1031 | def classify_incident(nodeid_s, (header,events)): |
|---|
| | 1032 | if "foom" in header["trigger"].get("message",""): |
|---|
| | 1033 | return "foom" |
|---|
| | 1034 | ''') |
|---|
| | 1035 | f.close() |
|---|
| 1026 | 1036 | ig2.setServiceParent(self.parent) |
|---|
| | 1037 | # now that it's been read, delete it to avoid affecting later |
|---|
| | 1038 | # runs |
|---|
| | 1039 | os.unlink(foomfile) |
|---|
| 1027 | 1040 | self.ig2 = ig2 |
|---|
| 1028 | 1041 | |
|---|
| … | … | |
| 1198 | 1211 | self.failUnless(data['d']["failure"].check(SampleError)) |
|---|
| 1199 | 1212 | self.failUnless("whoops2" in str(data['d']["failure"])) |
|---|
| | 1213 | |
|---|
| | 1214 | def test_wrongdir(self): |
|---|
| | 1215 | basedir = "logging/Gatherer/wrongdir" |
|---|
| | 1216 | os.makedirs(basedir) |
|---|
| | 1217 | |
|---|
| | 1218 | # create a LogGatherer with an unspecified basedir: it should look |
|---|
| | 1219 | # for a .tac file in the current directory, not see it, and complain |
|---|
| | 1220 | e = self.failUnlessRaises(RuntimeError, |
|---|
| | 1221 | MyGatherer, None, True, None) |
|---|
| | 1222 | self.failUnless("running in the wrong directory" in str(e)) |
|---|
| 1200 | 1223 | |
|---|
| 1201 | 1224 | def test_log_gatherer(self): |
|---|