Ver Fonte

Support syslog as a log target

Jason R. Coombs há 13 anos atrás
pai
commit
ed22e48b76
2 ficheiros alterados com 53 adições e 20 exclusões
  1. 17 14
      supervisor/dispatchers.py
  2. 36 6
      supervisor/loggers.py

+ 17 - 14
supervisor/dispatchers.py

@@ -4,7 +4,7 @@ from supervisor.medusa.asyncore_25 import compact_traceback
 from supervisor.events import notify
 from supervisor.events import EventRejectedEvent
 from supervisor.events import ProcessLogStderrEvent
-from supervisor.events import ProcessLogStdoutEvent 
+from supervisor.events import ProcessLogStdoutEvent
 from supervisor.states import EventListenerStates
 from supervisor import loggers
 
@@ -86,10 +86,13 @@ class POutputDispatcher(PDispatcher):
         if logfile:
             maxbytes = getattr(process.config, '%s_logfile_maxbytes' % channel)
             backups = getattr(process.config, '%s_logfile_backups' % channel)
+            fmt = '%(message)s'
+            if logfile == 'syslog':
+                fmt = ' '.join((process.config.name, fmt))
             self.mainlog = process.config.options.getLogger(
                 logfile,
                 loggers.LevelsByName.INFO,
-                '%(message)s',
+                fmt=fmt,
                 rotating=not not maxbytes, # optimization
                 maxbytes=maxbytes,
                 backups=backups)
@@ -144,13 +147,13 @@ class POutputDispatcher(PDispatcher):
             if self.channel == 'stdout':
                 if self.stdout_events_enabled:
                     notify(
-                        ProcessLogStdoutEvent(self.process, 
+                        ProcessLogStdoutEvent(self.process,
                             self.process.pid, data)
                     )
             else: # channel == stderr
                 if self.stderr_events_enabled:
                     notify(
-                        ProcessLogStderrEvent(self.process, 
+                        ProcessLogStderrEvent(self.process,
                             self.process.pid, data)
                     )
 
@@ -161,7 +164,7 @@ class POutputDispatcher(PDispatcher):
             self.output_buffer = ''
             self._log(data)
             return
-            
+
         if self.capturemode:
             token, tokenlen = self.endtoken_data
         else:
@@ -192,7 +195,7 @@ class POutputDispatcher(PDispatcher):
 
     def toggle_capturemode(self):
         self.capturemode = not self.capturemode
-    
+
         if self.capturelog is not None:
             if self.capturemode:
                 self.childlog = self.capturelog
@@ -204,7 +207,7 @@ class POutputDispatcher(PDispatcher):
                 procname = self.process.config.name
                 event = self.event_type(self.process, self.process.pid, data)
                 notify(event)
-                                        
+
                 msg = "%(procname)r %(channel)s emitted a comm event"
                 self.process.config.options.logger.debug(msg,
                                                          procname=procname,
@@ -216,7 +219,7 @@ class POutputDispatcher(PDispatcher):
 
     def writable(self):
         return False
-    
+
     def readable(self):
         if self.closed:
             return False
@@ -283,7 +286,7 @@ class PEventListenerDispatcher(PDispatcher):
 
     def writable(self):
         return False
-    
+
     def readable(self):
         if self.closed:
             return False
@@ -355,7 +358,7 @@ class PEventListenerDispatcher(PDispatcher):
             self.state_buffer = ''
             process.event = None
             return
-                
+
         elif state == EventListenerStates.BUSY:
             if self.resultlen is None:
                 # we haven't begun gathering result data yet
@@ -444,7 +447,7 @@ class PInputDispatcher(PDispatcher):
         sent = self.process.config.options.write(self.fd,
                                                  self.input_buffer)
         self.input_buffer = self.input_buffer[sent:]
-    
+
     def handle_write_event(self):
         if self.input_buffer:
             try:
@@ -457,9 +460,9 @@ class PInputDispatcher(PDispatcher):
                     raise
 
 ANSI_ESCAPE_BEGIN = '\x1b['
-ANSI_TERMINATORS = ('H', 'f', 'A', 'B', 'C', 'D', 'R', 's', 'u', 'J', 
-                    'K', 'h', 'l', 'p', 'm')    
-    
+ANSI_TERMINATORS = ('H', 'f', 'A', 'B', 'C', 'D', 'R', 's', 'u', 'J',
+                    'K', 'h', 'l', 'p', 'm')
+
 def stripEscapes(string):
     """
     Remove all ANSI color escapes from the given string.

+ 36 - 6
supervisor/loggers.py

@@ -13,6 +13,12 @@ import sys
 import time
 import traceback
 
+try:
+    import syslog
+except ImportError:
+    # only required when 'syslog' is specified as the log filename
+    pass
+
 class LevelsByName:
     CRIT = 50   # messages that probably require immediate user attention
     ERRO = 40   # messages that indicate a potentially ignorable error condition
@@ -106,7 +112,7 @@ class FileHandler(Handler):
 class StreamHandler(Handler):
     def __init__(self, strm=None):
         self.stream = strm
-        
+
     def remove(self):
         if hasattr(self.stream, 'clear'):
             self.stream.clear()
@@ -136,7 +142,7 @@ class BoundIO:
 
     def clear(self):
         self.buf = ''
-            
+
 class RotatingFileHandler(FileHandler):
 
     open_streams = {}
@@ -190,7 +196,7 @@ class RotatingFileHandler(FileHandler):
             Set open filehandle for filename defined on the
             RotatingFileHandler
             """
-            obj.open_streams[obj.baseFilename] = stream        
+            obj.open_streams[obj.baseFilename] = stream
 
     stream = _stream()
 
@@ -285,11 +291,11 @@ class Logger:
     def trace(self, msg, **kw):
         if LevelsByName.TRAC >= self.level:
             self.log(LevelsByName.TRAC, msg, **kw)
-    
+
     def debug(self, msg, **kw):
         if LevelsByName.DEBG >= self.level:
             self.log(LevelsByName.DEBG, msg, **kw)
-    
+
     def info(self, msg, **kw):
         if LevelsByName.INFO >= self.level:
             self.log(LevelsByName.INFO, msg, **kw)
@@ -318,13 +324,34 @@ class Logger:
     def getvalue(self):
         raise NotImplementedError
 
+class SyslogHandler(Handler):
+    def __init__(self):
+        assert 'syslog' in globals(), "Syslog module not present"
+
+    def close(self):
+        pass
+
+    def emit(self, record):
+        try:
+            params = record.asdict()
+            message = params['message']
+            for line in message.rstrip('\n').split('\n'):
+                params['message'] = line
+                msg = self.fmt % params
+                try:
+                    syslog.syslog(msg)
+                except UnicodeError:
+                    syslog.syslog(msg.encode("UTF-8"))
+        except:
+            self.handleError(record)
+
 def getLogger(filename, level, fmt, rotating=False, maxbytes=0, backups=0,
               stdout=False):
 
     handlers = []
 
     logger = Logger(level)
-    
+
     if filename is None:
         if not maxbytes:
             maxbytes = 1<<21 #2MB
@@ -332,6 +359,9 @@ def getLogger(filename, level, fmt, rotating=False, maxbytes=0, backups=0,
         handlers.append(StreamHandler(io))
         logger.getvalue = io.getvalue
 
+    elif filename == 'syslog':
+        handlers.append(SyslogHandler())
+
     else:
         if rotating is False:
             handlers.append(FileHandler(filename))