1 #!/usr/bin/env python |
|
2 |
|
3 """ |
|
4 Syslog -> Irk |
|
5 """ |
|
6 |
|
7 __version__ = '0.0' |
|
8 |
|
9 import pvl.args |
|
10 import pvl.syslog.args |
|
11 import pvl.syslog.rule |
|
12 import pvl.irk |
|
13 |
|
14 import logging, optparse |
|
15 |
|
16 log = logging.getLogger('main') |
|
17 |
|
18 def parse_options (argv) : |
|
19 """ |
|
20 Parse command-line arguments. |
|
21 """ |
|
22 |
|
23 prog = argv[0] |
|
24 |
|
25 parser = optparse.OptionParser( |
|
26 prog = prog, |
|
27 usage = '%prog: [options]', |
|
28 version = __version__, |
|
29 |
|
30 # module docstring |
|
31 description = __doc__, |
|
32 ) |
|
33 |
|
34 # options |
|
35 parser.add_option_group(pvl.args.parser(parser)) |
|
36 |
|
37 # input |
|
38 parser.add_option_group(pvl.syslog.args.parser(parser)) |
|
39 parser.add_option_group(pvl.syslog.rule.parser(parser)) |
|
40 parser.add_option_group(pvl.irk.parser(parser, connect=None)) |
|
41 |
|
42 parser.add_option('--irker-target', metavar='IRC', |
|
43 help="Irker target URL") |
|
44 |
|
45 # parse |
|
46 options, args = parser.parse_args(argv[1:]) |
|
47 |
|
48 # apply |
|
49 pvl.args.apply(options, prog, rootok=False) |
|
50 |
|
51 return options, args |
|
52 |
|
53 def apply_irker (irker) : |
|
54 """ |
|
55 Handle irker activity. |
|
56 """ |
|
57 |
|
58 for msg in irker.irk : |
|
59 log.info("irk: %s", msg) |
|
60 |
|
61 def apply_syslog (options, syslog, rules, irker) : |
|
62 """ |
|
63 Handle syslog activity. |
|
64 """ |
|
65 |
|
66 # syslogs |
|
67 for item in syslog : |
|
68 match, rulepath, apply = rules.apply(item) |
|
69 |
|
70 log.debug("%s: %s: %s", item, rulepath, apply) |
|
71 |
|
72 target = apply.get('irk', options.irker_target) |
|
73 |
|
74 tag = '/'.join(str(rule) for rule in reversed(rulepath[:-1])) |
|
75 text = apply.get('text') |
|
76 |
|
77 log.info("%s: %s: %s", target, tag, text) |
|
78 |
|
79 if not text : |
|
80 # XXX: plain irk = ... in rule is broken, as it always applies, and skips any further rules |
|
81 continue |
|
82 |
|
83 if irker and target : |
|
84 irker[target]('[' + tag + '] ' + text) |
|
85 else : |
|
86 print tag, text |
|
87 |
|
88 def close_irker (irker) : |
|
89 """ |
|
90 Shutdown irker before quitting. |
|
91 |
|
92 XXX: irker.close() to disconnect? |
|
93 """ |
|
94 |
|
95 log.info("Shutting down IRK...") |
|
96 |
|
97 for target in list(irker) : |
|
98 log.warn("%s", target) |
|
99 del irker[target] |
|
100 |
|
101 def close_syslog (syslog) : |
|
102 """ |
|
103 Shutdown syslog before quitting |
|
104 """ |
|
105 |
|
106 # XXX: do all sources support close()? |
|
107 log.warn("%s", syslog) |
|
108 syslog.close() |
|
109 |
|
110 def main (argv) : |
|
111 options, args = parse_options(argv) |
|
112 |
|
113 # no args |
|
114 if args : |
|
115 log.error("Usage: pvl.irker-syslog [options]") |
|
116 return 2 |
|
117 |
|
118 # setup |
|
119 log.info("Open syslog...") |
|
120 syslog = pvl.syslog.args.apply(options) |
|
121 |
|
122 log.info("Load rules...") |
|
123 rules = pvl.syslog.rule.apply(options) |
|
124 |
|
125 log.info("Connect IRK..") |
|
126 irker = pvl.irk.apply(options) |
|
127 |
|
128 if options.irker_target : |
|
129 # pre-join target |
|
130 irker[options.irker_target] |
|
131 |
|
132 log.info("Process syslog messages...") |
|
133 |
|
134 # customized mainloop that supports irker.irk |
|
135 while True : |
|
136 try : |
|
137 # TODO: seprate IrkError, to not confuse irk write vs syslog read eof |
|
138 apply_syslog(options, syslog, rules, irker) |
|
139 |
|
140 except EOFError as ex : |
|
141 log.error("syslog: EOF") |
|
142 |
|
143 close_irker(irker) |
|
144 |
|
145 # 0 is controlled exit |
|
146 return 0 |
|
147 |
|
148 except pvl.irk.IrkError as ex : |
|
149 log.error("irker: %s", ex) |
|
150 |
|
151 # XXX: copy-pasta |
|
152 close_syslog(syslog) |
|
153 return 0 |
|
154 |
|
155 # quit unless we have something to poll |
|
156 if not syslog.poll : |
|
157 break |
|
158 |
|
159 # is irk pollable? |
|
160 if irker.irk.recv : |
|
161 reading = (irker.irk, ) |
|
162 else : |
|
163 reading = () |
|
164 |
|
165 poll = syslog.select(syslog.poll, reading=reading) or () # timeout -> () |
|
166 |
|
167 if irker.irk in poll : |
|
168 # irks? |
|
169 try : |
|
170 apply_irker(irker) |
|
171 |
|
172 except EOFError : |
|
173 log.error("irk: EOF") |
|
174 |
|
175 close_syslog(syslog) |
|
176 |
|
177 # exit 0, so as to restart sooner |
|
178 # XXX: maybe use a special exit code instead? |
|
179 return 0 |
|
180 |
|
181 # done |
|
182 log.info("Exiting...") |
|
183 return 0 |
|
184 |
|
185 if __name__ == '__main__': |
|
186 import sys |
|
187 |
|
188 sys.exit(main(sys.argv)) |
|