Skip to content

Commit 8719db9

Browse files
committed
feat(logging): add customizable log formats for main and child logs
1 parent 83ddb1e commit 8719db9

File tree

5 files changed

+55
-11
lines changed

5 files changed

+55
-11
lines changed

supervisor/dispatchers.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,13 @@ def __init__(self, process, event_type, fd):
105105
self.endtoken_data = (endtoken, len(endtoken))
106106
self.mainlog_level = loggers.LevelsByName.DEBG
107107
config = self.process.config
108-
self.log_to_mainlog = config.options.loglevel <= self.mainlog_level
108+
# Handle case where options haven't been realized yet
109+
loglevel = getattr(config.options, 'loglevel', None)
110+
if loglevel is None:
111+
# Default loglevel when not set
112+
from supervisor.loggers import LevelsByName
113+
loglevel = LevelsByName.INFO
114+
self.log_to_mainlog = loglevel <= self.mainlog_level
109115
self.stdout_events_enabled = config.stdout_events_enabled
110116
self.stderr_events_enabled = config.stderr_events_enabled
111117

@@ -126,7 +132,9 @@ def _init_normallog(self):
126132
self.normallog = config.options.getLogger()
127133

128134
if logfile:
129-
fmt = config.options.childlog_format
135+
fmt = getattr(config.options, 'childlog_format', None)
136+
if fmt is None:
137+
fmt = '%(message)s' # Default format
130138
loggers.handle_file(
131139
self.normallog,
132140
filename=logfile,
@@ -137,7 +145,10 @@ def _init_normallog(self):
137145
)
138146

139147
if to_syslog:
140-
fmt = config.name + ' ' + config.options.childlog_format
148+
childlog_format = getattr(config.options, 'childlog_format', None)
149+
if childlog_format is None:
150+
childlog_format = '%(message)s' # Default format
151+
fmt = config.name + ' ' + childlog_format
141152
loggers.handle_syslog(
142153
self.normallog,
143154
fmt=fmt

supervisor/loggers.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,12 @@ class FileHandler(Handler):
153153
"""File handler which supports reopening of logs.
154154
"""
155155

156-
def __init__(self, filename, mode='ab'):
156+
def __init__(self, filename, mode='ab', fmt=None):
157157
Handler.__init__(self)
158158

159+
if fmt is not None:
160+
self.setFormat(fmt)
161+
159162
try:
160163
self.stream = open(filename, mode)
161164
except OSError as e:
@@ -187,7 +190,7 @@ def remove(self):
187190

188191
class RotatingFileHandler(FileHandler):
189192
def __init__(self, filename, mode='ab', maxBytes=512*1024*1024,
190-
backupCount=10):
193+
backupCount=10, fmt=None):
191194
"""
192195
Open the specified file and use it as the stream for logging.
193196
@@ -210,7 +213,7 @@ def __init__(self, filename, mode='ab', maxBytes=512*1024*1024,
210213
"""
211214
if maxBytes > 0:
212215
mode = 'ab' # doesn't make sense otherwise!
213-
FileHandler.__init__(self, filename, mode)
216+
FileHandler.__init__(self, filename, mode, fmt)
214217
self.maxBytes = maxBytes
215218
self.backupCount = backupCount
216219
self.counter = 0
@@ -388,8 +391,18 @@ def emit(self, record):
388391
except:
389392
self.handleError()
390393

391-
def getLogger(level=None):
392-
return Logger(level)
394+
def getLogger(level=None, fmt=None):
395+
logger = Logger(level)
396+
if fmt is not None:
397+
# Create a handler with the specified format
398+
handler = StreamHandler()
399+
handler.setFormat(fmt)
400+
if level is not None:
401+
handler.setLevel(level)
402+
else:
403+
handler.setLevel(logger.level)
404+
logger.addHandler(handler)
405+
return logger
393406

394407
_2MB = 1<<21
395408

@@ -409,6 +422,13 @@ def handle_stdout(logger, fmt):
409422
handler.setLevel(logger.level)
410423
logger.addHandler(handler)
411424

425+
def handle_stderr(logger, fmt):
426+
"""Attach a new StreamHandler with stderr handler to an existing Logger"""
427+
handler = StreamHandler(sys.stderr)
428+
handler.setFormat(fmt)
429+
handler.setLevel(logger.level)
430+
logger.addHandler(handler)
431+
412432
def handle_syslog(logger, fmt):
413433
"""Attach a new Syslog handler to an existing Logger"""
414434
handler = SyslogHandler()

supervisor/options.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -544,10 +544,15 @@ def realize(self, *arg, **kw):
544544
# Configure the main logger
545545
self.logger = loggers.getLogger(loglevel)
546546

547+
if self.logfile:
548+
logfile = self.logfile
549+
else:
550+
logfile = section.logfile
551+
547552
if logfile:
548553
loggers.handle_file(
549554
self.logger,
550-
self.logfile,
555+
logfile,
551556
logfile_format,
552557
rotating=True,
553558
maxbytes=section.logfile_maxbytes,
@@ -677,8 +682,10 @@ def get(opt, default, **kwargs):
677682
section.identifier = get('identifier', 'supervisor')
678683
section.nodaemon = boolean(get('nodaemon', 'false'))
679684
section.logfile_format = get('logfile_format',
680-
'%(asctime)s %(levelname)s %(message)s')
681-
section.childlog_format = get('childlog_format', '%(message)s')
685+
'%(asctime)s %(levelname)s %(message)s',
686+
do_expand=False)
687+
section.childlog_format = get('childlog_format', '%(message)s',
688+
do_expand=False)
682689
section.silent = boolean(get('silent', 'false'))
683690

684691
tempdir = tempfile.gettempdir()

supervisor/tests/base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ def __init__(self):
8989
self.umaskset = None
9090
self.poller = DummyPoller(self)
9191
self.silent = False
92+
self.childlog_format = '%(message)s'
9293

9394
def getLogger(self, *args, **kw):
9495
logger = DummyLogger()

supervisor/tests/test_options.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3411,7 +3411,12 @@ def test_daemonize_notifies_poller_before_and_after_fork(self):
34113411

34123412
def test_default_log_format_options(self):
34133413
"""Test that default log format options are set correctly"""
3414+
text = lstrip('''
3415+
[supervisord]
3416+
logfile=/tmp/supervisord.log
3417+
''')
34143418
instance = self._makeOne()
3419+
instance.configfile = StringIO(text)
34153420
instance.realize(args=[])
34163421
options = instance.configroot.supervisord
34173422
self.assertEqual(options.logfile_format, '%(asctime)s %(levelname)s %(message)s')

0 commit comments

Comments
 (0)