| Trees | Indices | Help |
|
|---|
|
|
1 #! /usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # ##########################################################################
4 #
5 # This program is part of Zenoss Core, an open source monitoring platform.
6 # Copyright (C) 2008, Zenoss Inc.
7 #
8 # This program is free software; you can redistribute it and/or modify it
9 # under the terms of the GNU General Public License version 2 as published by
10 # the Free Software Foundation.
11 #
12 # For complete information please visit: http://www.zenoss.com/oss/
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
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
83 """
84 Initialize the daemon
85
86 @return: Twisted deferred object
87 @rtype: Twisted deferred object
88 """
89 def inner(driver):
90 """
91 Generator function to gather zProperites and then initialize.
92
93 @param driver: driver
94 @type driver: string
95 @return: Twisted deferred object
96 @rtype: Twisted deferred object
97 """
98 yield EventServer.configure(self)
99 driver.next()
100 self.log.info('Fetching the default syslog priority')
101 yield self.model().callRemote('getDefaultPriority')
102 self.processor = SyslogProcessor(self.sendEvent,
103 self.options.minpriority, self.options.parsehost,
104 self.options.monitor, driver.next())
105 self.log.info('Configuration finished')
106
107 return drive(inner)
108
109
111 """
112 Expands a syslog message into a string format suitable for writing
113 to the filesystem such that it appears the same as it would
114 had the message been logged by the syslog daemon.
115
116 @param msg: syslog message
117 @type msg: string
118 @param client_address: IP info of the remote device (ipaddr, port)
119 @type client_address: tuple of (string, number)
120 @return: message
121 @rtype: string
122 """
123 # pri := facility * severity
124 stop = msg.find('>')
125
126 # check for a datestamp. default to right now if date not present
127 start = stop + 1
128 stop = start + len(ZenSyslog.SAMPLE_DATE)
129 dateField = msg[start:stop]
130 try:
131 date = time.strptime(dateField,
132 ZenSyslog.SYSLOG_DATE_FORMAT)
133 year = time.localtime()[0]
134 date = (year, ) + date[1:]
135 start = stop + 1
136 except ValueError:
137
138 # date not present, so use today's date
139 date = time.localtime()
140
141 # check for a hostname. default to localhost if not present
142 stop = msg.find(' ', start)
143 if msg[stop - 1] == ':':
144 hostname = client_address[0]
145 else:
146 hostname = msg[start:stop]
147 start = stop + 1
148
149 # the message content
150 body = msg[start:]
151
152 # assemble the message
153 prettyTime = time.strftime(ZenSyslog.SYSLOG_DATE_FORMAT, date)
154 message = '%s %s %s' % (prettyTime, hostname, body)
155 return message
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
| Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0beta1 on Thu May 7 11:46:47 2009 | http://epydoc.sourceforge.net |