This is because things like the fedmsg-hub are daemons, and will double-fork into the background. If we determine the process at startup time, that original process is long dead by the time we get to the first log statement.
144 lines
4.4 KiB
Django/Jinja
144 lines
4.4 KiB
Django/Jinja
# Setup fedmsg logging.
|
|
|
|
# All of these modules are just used by the ContextInjector below.
|
|
import inspect
|
|
import logging
|
|
import os
|
|
import psutil
|
|
import socket
|
|
import traceback
|
|
|
|
|
|
class ContextInjector(logging.Filter):
|
|
""" Logging filter that adds context to log records.
|
|
|
|
Filters are typically used to "filter" log records. They declare a filter
|
|
method that can return True or False. Only records with 'True' will
|
|
actually be logged.
|
|
|
|
Here, we somewhat abuse the concept of a filter. We always return true,
|
|
but we use the opportunity to hang important contextual information on the
|
|
log record to later be used by the logging Formatter. We don't normally
|
|
want to see all this stuff in normal log records, but we *do* want to see
|
|
it when we are emailed error messages. Seeing an error, but not knowing
|
|
which host it comes from, is not that useful.
|
|
|
|
http://docs.python.org/2/howto/logging-cookbook.html#filters-contextual
|
|
"""
|
|
|
|
def filter(self, record):
|
|
current_process = ContextInjector.get_current_process()
|
|
current_hostname = socket.gethostname()
|
|
|
|
record.host = current_hostname
|
|
record.proc = current_process
|
|
record.pid = current_process.pid
|
|
record.proc_name = current_process.name
|
|
record.command_line = " ".join(current_process.cmdline)
|
|
record.callstack = self.format_callstack()
|
|
return True
|
|
|
|
@staticmethod
|
|
def format_callstack():
|
|
for i, frame in enumerate(f[0] for f in inspect.stack()):
|
|
if not '__name__' in frame.f_globals:
|
|
continue
|
|
modname = frame.f_globals['__name__'].split('.')[0]
|
|
if modname != "logging":
|
|
break
|
|
|
|
def _format_frame(frame):
|
|
return ' File "%s", line %i in %s\n %s' % (frame)
|
|
|
|
stack = traceback.extract_stack()
|
|
stack = stack[:-i]
|
|
return "\n".join([_format_frame(frame) for frame in stack])
|
|
|
|
@staticmethod
|
|
def get_current_process():
|
|
mypid = os.getpid()
|
|
for proc in psutil.process_iter():
|
|
if proc.pid == mypid:
|
|
return proc
|
|
|
|
# This should be impossible.
|
|
raise ValueError("Could not find process %r" % mypid)
|
|
|
|
@classmethod
|
|
def __json__(cls):
|
|
""" We need to be jsonifiable for "fedmsg-config" """
|
|
return {'name': 'ContextInjector'}
|
|
|
|
|
|
hefty_format = """Message
|
|
-------
|
|
[%(asctime)s][%(name)10s %(levelname)7s]
|
|
%(message)s
|
|
|
|
Process Details
|
|
---------------
|
|
host: %(host)s
|
|
PID: %(pid)s
|
|
name: %(proc_name)s
|
|
command: %(command_line)s
|
|
|
|
Callstack that lead to the logging statement
|
|
--------------------------------------------
|
|
%(callstack)s
|
|
"""
|
|
|
|
|
|
# See the following for constraints on this format http://bit.ly/Xn1WDn
|
|
config = dict(
|
|
logging=dict(
|
|
version=1,
|
|
formatters=dict(
|
|
bare={
|
|
"datefmt": "%Y-%m-%d %H:%M:%S",
|
|
"format": "[%(asctime)s][%(name)10s %(levelname)7s] %(message)s"
|
|
},
|
|
hefty={
|
|
"datefmt": "%Y-%m-%d %H:%M:%S",
|
|
"format": hefty_format,
|
|
},
|
|
),
|
|
filters=dict(
|
|
context={
|
|
# This "()" syntax in the stdlib doesn't seem to be documented
|
|
# anywhere. I had to read
|
|
# /usr/lib64/python2.7/logging/config.py to figure it out.
|
|
"()": ContextInjector,
|
|
},
|
|
),
|
|
handlers=dict(
|
|
console={
|
|
"class": "logging.StreamHandler",
|
|
"formatter": "bare",
|
|
"level": "DEBUG",
|
|
"stream": "ext://sys.stdout",
|
|
},
|
|
mailer={
|
|
"class": "logging.handlers.SMTPHandler",
|
|
"formatter": "hefty",
|
|
"filters": ["context"],
|
|
"level": "ERROR",
|
|
"mailhost": "bastion.phx2.fedoraproject.org",
|
|
"fromaddr": "fedmsg@fedoraproject.org",
|
|
"toaddrs": ["sysadmin-datanommer-members@fedoraproject.org"],
|
|
"subject": "fedmsg error log",
|
|
},
|
|
),
|
|
loggers=dict(
|
|
fedmsg={
|
|
"level": "DEBUG",
|
|
"propagate": False,
|
|
"handlers": ["console", "mailer"],
|
|
},
|
|
moksha={
|
|
"level": "DEBUG",
|
|
"propagate": False,
|
|
"handlers": ["console", "mailer"],
|
|
},
|
|
),
|
|
),
|
|
)
|