"""A minimalistic syslogd. 2000-06-09/bb: created 2000-06-12/bb: added constants from syslog.h, config options for time format, stop string """ import sys, string, time, socket, re from SocketServer import * # constants from syslog.h LOG_EMERG = 0 LOG_ALERT = 1 LOG_CRIT = 2 LOG_ERR = 3 LOG_WARNING = 4 LOG_NOTICE = 5 LOG_INFO = 6 LOG_DEBUG = 7 LOG_PRIMASK = 0x07 def LOG_PRI(p): return p & LOG_PRIMASK def LOG_MAKEPRI(fac, pri): return fac << 3 | pri LOG_KERN = 0 << 3 LOG_USER = 1 << 3 LOG_MAIL = 2 << 3 LOG_DAEMON = 3 << 3 LOG_AUTH = 4 << 3 LOG_SYSLOG = 5 << 3 LOG_LPR = 6 << 3 LOG_NEWS = 7 << 3 LOG_UUCP = 8 << 3 LOG_CRON = 9 << 3 LOG_AUTHPRIV = 10 << 3 LOG_FTP = 11 << 3 LOG_LOCAL0 = 16 << 3 LOG_LOCAL1 = 17 << 3 LOG_LOCAL2 = 18 << 3 LOG_LOCAL3 = 19 << 3 LOG_LOCAL4 = 20 << 3 LOG_LOCAL5 = 21 << 3 LOG_LOCAL6 = 22 << 3 LOG_LOCAL7 = 23 << 3 LOG_NFACILITIES = 24 LOG_FACMASK = 0x03F8 def LOG_FAC(p): return (p & LOG_FACMASK) >> 3 def LOG_MASK(pri): return 1 << pri def LOG_UPTO(pri): return (1 << pri + 1) - 1 # end syslog.h def LOG_UNPACK(p): return (p & LOG_FACMASK, LOG_PRI(p)) fac_values = {} # mapping of facility constants to their values fac_names = {} # mapping of values to names pri_values = {} pri_names = {} for i, j in globals().items(): if i[:4] == 'LOG_' and type(j) == type(0): if j > LOG_PRIMASK or i == 'LOG_KERN': n, v = fac_names, fac_values else: n, v = pri_names, pri_values i = i[4:].lower() v[i] = j n[j] = i del i, j, n, v conf_pat = re.compile(r''' ^\s* # leading space ([\w*]+) # facility \.([=!]?) # separator plus optional modifier ([\w*]+) # priority \s+ ([|@]?) # target type fifo/remote host (\S+) # target ''', re.VERBOSE) class InterruptibleServer: "Mix-in class for {TCP,UDP}Server that allows to stop the service" def serve(self): "Run the service until it is stopped with the stop() method." self.running = 1 while self.running: try: self.handle_request() except KeyboardInterrupt: self.stop() def stop(self): # called by handle_request() "Stop the service." self.running = 0 SYSLOG_PORT = socket.getservbyname('syslog', 'udp') class Syslogd(ThreadingUDPServer, InterruptibleServer): def __init__(self, addr='', port=SYSLOG_PORT, pri=LOG_DEBUG, timefmt=None, magic=None): UDPServer.__init__(self, (addr, port), None) self.hostmap = {} # client address/name mapping self.priority = pri self.timefmt = timefmt or '%b %d %H:%M:%S' self.stop_magic = magic or '_stop' print 'syslogd started' def finish_request(self, (msg, sock), client_address): # get the time when the message arrives tm = time.time() # Messages are in the form "[[float]]<int>message text...\n" # The [[float]] and <int> parts and the newline are optional. # The float denotes the original event time in case the # event comes through a gateway from a client that is not # syslog-compatible (Windows NT comes to mind :-). # extract original event time, if present if msg[:2] == '[[': pos = msg.find(']]') try: tm = float(msg[2:pos]) except: pass msg = msg[pos+2:] # use rest of message # extract log facility and priority, if present if msg[:1] == '<': pos = msg.find('>') fac, pri = LOG_UNPACK(int(msg[1:pos])) msg = msg[pos+1:] elif msg and msg[0] < ' ': fac, pri = LOG_KERN, ord(msg[0]) msg = msg[1:] else: fac, pri = None, None # check if we can discard this message if pri is not None and pri > self.priority: return # build the client address/name mapping client = client_address[0] try: host = self.hostmap[client] except KeyError: try: host = socket.gethostbyaddr(client)[0] host = host.split('.')[0] # keep only the host name except socket.error: host = client self.hostmap[client] = host # print the message tm = time.strftime(self.timefmt, time.localtime(tm)) if 0: # fac is not None and pri is not None: fp = ' <%s,%s>' % (fac_names[fac], pri_names[pri]) else: fp = '' sys.stdout.write(tm + ' ' + host + fp + ': ' + msg.strip() + '\n') # stop the server if the magic stop string appears in the message if msg.find(self.stop_magic) >= 0: print 'stopped.' self.stop() if __name__ == '__main__': Syslogd(timefmt='%H:%M:%S').serve()