1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 __doc__ = """zensyslog
17
18 Turn syslog messages into events.
19
20 """
21
22 import time
23 import socket
24
25 from twisted.internet.protocol import DatagramProtocol
26 from twisted.internet import reactor
27 from twisted.python import failure
28 from twisted.internet import defer
29
30 import Globals
31 from Products.ZenEvents.EventServer import EventServer
32 from Products.ZenEvents.SyslogProcessing import SyslogProcessor
33
34 from Products.ZenUtils.Utils import zenPath
35 from Products.ZenUtils.IpUtil import asyncNameLookup
36 from Products.ZenUtils.Driver import drive
37
38 SYSLOG_PORT = 514
39 try:
40 SYSLOG_PORT = socket.getservbyname('syslog', 'udp')
41 except socket.error:
42 pass
43
44
45 -class ZenSyslog(DatagramProtocol, EventServer):
46 """
47 ZenSyslog
48 """
49
50 name = 'zensyslog'
51 SYSLOG_DATE_FORMAT = '%b %d %H:%M:%S'
52 SAMPLE_DATE = 'Apr 10 15:19:22'
53
55 EventServer.__init__(self)
56 if not self.options.useFileDescriptor\
57 and self.options.syslogport < 1024:
58 self.openPrivilegedPort('--listen', '--proto=udp',
59 '--port=%s:%d'
60 % (self.options.listenip,
61 self.options.syslogport))
62 self.changeUser()
63 self.minpriority = self.options.minpriority
64 self.processor = None
65
66 if self.options.logorig:
67 import logging
68 self.olog = logging.getLogger('origsyslog')
69 self.olog.setLevel(20)
70 self.olog.propagate = False
71 lname = zenPath('log/origsyslog.log')
72 hdlr = logging.FileHandler(lname)
73 hdlr.setFormatter(logging.Formatter('%(message)s'))
74 self.olog.addHandler(hdlr)
75 if self.options.useFileDescriptor is not None:
76 self.useUdpFileDescriptor(int(self.options.useFileDescriptor))
77 else:
78 reactor.listenUDP(self.options.syslogport, self,
79 interface=self.options.listenip)
80
81
106
107 return drive(inner)
108
109
110 - def expand(self, msg, client_address):
156
157
159 """
160 Consume the network packet
161
162 @param msg: syslog message
163 @type msg: string
164 @param client_address: IP info of the remote device (ipaddr, port)
165 @type client_address: tuple of (string, number)
166 """
167 (ipaddr, port) = client_address
168 if self.options.logorig:
169 if self.options.logformat == 'human':
170 message = self.expand(msg, client_address)
171 else:
172 message = msg
173 self.olog.info(message)
174
175 if self.options.noreverseLookup:
176 d = defer.succeed(ipaddr)
177 else:
178 d = asyncNameLookup(ipaddr)
179 d.addBoth(self.gotHostname, (msg, ipaddr, time.time()))
180
181
183 """
184 Send the resolved address, if possible, and the event via the thread
185
186 @param response: Twisted response
187 @type response: Twisted response
188 @param data: (msg, ipaddr, rtime)
189 @type data: tuple of (string, string, datetime object)
190 """
191 (msg, ipaddr, rtime) = data
192 if isinstance(response, failure.Failure):
193 host = ipaddr
194 else:
195 host = response
196 if self.processor:
197 self.processor.process(msg, ipaddr, host, rtime)
198
199
201 """
202 Command-line options
203 """
204 EventServer.buildOptions(self)
205 self.parser.add_option('--dmdpath', dest='dmdpath',
206 default='/zport/dmd',
207 help='Zope path to our DMD /zport/dmd')
208 self.parser.add_option('--parsehost', dest='parsehost',
209 action='store_true', default=False,
210 help='Try to parse the hostname part of a syslog HEADER'
211 )
212 self.parser.add_option('--stats', dest='stats',
213 action='store_true', default=False,
214 help='Print statistics to log every 2 secs')
215 self.parser.add_option('--logorig', dest='logorig',
216 action='store_true', default=False,
217 help='Log the original message')
218 self.parser.add_option('--logformat', dest='logformat',
219 default='human',
220 help='Human-readable (/var/log/messages) or raw (wire)'
221 )
222 self.parser.add_option('--minpriority', dest='minpriority',
223 default=6, type='int',
224 help='Minimum priority message that zensyslog will accept'
225 )
226 self.parser.add_option('--heartbeat', dest='heartbeat',
227 default=60,
228 help='Number of seconds between heartbeats'
229 )
230 self.parser.add_option('--syslogport', dest='syslogport',
231 default=SYSLOG_PORT, type='int',
232 help='Port number to use for syslog events'
233 )
234 self.parser.add_option('--listenip', dest='listenip',
235 default='0.0.0.0',
236 help='IP address to listen on. Default is 0.0.0.0'
237 )
238 self.parser.add_option('--useFileDescriptor',
239 dest='useFileDescriptor', type='int',
240 help='Read from an existing connection rather opening a new port.'
241 , default=None)
242 self.parser.add_option('--noreverseLookup', dest='noreverseLookup',
243 action='store_true', default=False,
244 help="Don't convert the remote device's IP address to a hostname."
245 )
246
247
248 if __name__ == '__main__':
249 zsl = ZenSyslog()
250 zsl.run()
251 zsl.report()
252