refactor: clean up logging (#7419)

* fix: log to stdout/stderr in json format

* chore: remove UTILS_LOGGER_LEVELS

This is not used (there _is_ a setting for the
django.security logger in settings_local.py on
production, but it is redundant with the
settings.LOGGING configuration and is not doing
anything).

* chore: revert to debug_console django logging

* chore: log.log to syslog via datatracker logger

* chore: remove unused imports

---------

Co-authored-by: Robert Sparks <rjsparks@nostrum.com>
This commit is contained in:
Jennifer Richards 2024-05-14 20:47:40 -03:00 committed by GitHub
parent 235ac8b2a6
commit 48e0aa23f5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 28 additions and 79 deletions

View file

@ -236,7 +236,7 @@ LOGGING = {
# #
'loggers': { 'loggers': {
'django': { 'django': {
'handlers': ['debug_console', 'mail_admins'], 'handlers': ['debug_console', 'mail_admins',],
'level': 'INFO', 'level': 'INFO',
}, },
'django.request': { 'django.request': {
@ -248,13 +248,17 @@ LOGGING = {
'level': 'INFO', 'level': 'INFO',
}, },
'django.security': { 'django.security': {
'handlers': ['debug_console', ], 'handlers': ['debug_console', ],
'level': 'INFO',
},
'oidc_provider': {
'handlers': ['debug_console', ],
'level': 'DEBUG',
},
'datatracker': {
'handlers': ['syslog'],
'level': 'INFO', 'level': 'INFO',
}, },
'oidc_provider': {
'handlers': ['debug_console', ],
'level': 'DEBUG',
},
}, },
# #
# No logger filters # No logger filters
@ -263,14 +267,7 @@ LOGGING = {
'console': { 'console': {
'level': 'DEBUG', 'level': 'DEBUG',
'class': 'logging.StreamHandler', 'class': 'logging.StreamHandler',
'formatter': 'plain', 'formatter': 'json',
},
'syslog': {
'level': 'DEBUG',
'class': 'logging.handlers.SysLogHandler',
'facility': 'user',
'formatter': 'plain',
'address': '/dev/log',
}, },
'debug_console': { 'debug_console': {
# Active only when DEBUG=True # Active only when DEBUG=True
@ -284,6 +281,13 @@ LOGGING = {
'class': 'logging.StreamHandler', 'class': 'logging.StreamHandler',
'formatter': 'django.server', 'formatter': 'django.server',
}, },
'syslog': {
'level': 'DEBUG',
'class': 'logging.handlers.SysLogHandler',
'facility': 'user',
'formatter': 'plain',
'address': '/dev/log',
},
'mail_admins': { 'mail_admins': {
'level': 'ERROR', 'level': 'ERROR',
'filters': [ 'filters': [
@ -325,18 +329,12 @@ LOGGING = {
'style': '{', 'style': '{',
'format': '{levelname}: {name}:{lineno}: {message}', 'format': '{levelname}: {name}:{lineno}: {message}',
}, },
'json' : {
'()': 'pythonjsonlogger.jsonlogger.JsonFormatter'
}
}, },
} }
# This should be overridden by settings_local for any logger where debug (or
# other) custom log settings are wanted. Use "ietf/manage.py showloggers -l"
# to show registered loggers. The content here should match the levels above
# and is shown as an example:
UTILS_LOGGER_LEVELS: Dict[str, str] = {
# 'django': 'INFO',
# 'django.server': 'INFO',
}
# End logging # End logging
# ------------------------------------------------------------------------ # ------------------------------------------------------------------------

View file

@ -9,37 +9,10 @@ import inspect
import os.path import os.path
import traceback import traceback
from typing import Callable # pyflakes:ignore
try:
import syslog
logfunc = syslog.syslog # type: Callable
except ImportError: # import syslog will fail on Windows boxes
logging.basicConfig(filename='tracker.log',level=logging.INFO)
logfunc = logging.info
pass
from django.conf import settings from django.conf import settings
import debug # pyflakes:ignore import debug # pyflakes:ignore
formatter = logging.Formatter('{levelname}: {name}:{lineno}: {message}', style='{')
for name, level in settings.UTILS_LOGGER_LEVELS.items():
logger = logging.getLogger(name)
if not logger.hasHandlers():
debug.say(' Adding handlers to logger %s' % logger.name)
handlers = [
logging.StreamHandler(),
logging.handlers.SysLogHandler(address='/dev/log',
facility=logging.handlers.SysLogHandler.LOG_USER),
]
for h in handlers:
h.setFormatter(formatter)
h.setLevel(level)
logger.addHandler(h)
debug.say(" Setting %s logging level to %s" % (logger.name, level))
logger.setLevel(level)
def getclass(frame): def getclass(frame):
cls = None cls = None
@ -56,20 +29,9 @@ def getcaller():
return (pmodule, pclass, pfunction, pfile, pline) return (pmodule, pclass, pfunction, pfile, pline)
def log(msg, e=None): def log(msg, e=None):
"Uses syslog by preference. Logs the given calling point and message." "Logs the given calling point and message to the logging framework's datatracker handler at severity INFO"
global logfunc if settings.SERVER_MODE == 'test' and not getattr(settings, 'show_logging',False):
def _flushfunc():
pass
_logfunc = logfunc
if settings.SERVER_MODE == 'test':
if getattr(settings, 'show_logging', False) is True:
_logfunc = debug.say
_flushfunc = sys.stdout.flush # pyflakes:ignore (intentional redefinition)
else:
return return
elif settings.DEBUG == True:
_logfunc = debug.say
_flushfunc = sys.stdout.flush # pyflakes:ignore (intentional redefinition)
if not isinstance(msg, str): if not isinstance(msg, str):
msg = msg.encode('unicode_escape') msg = msg.encode('unicode_escape')
try: try:
@ -82,11 +44,8 @@ def log(msg, e=None):
where = " in " + func + "()" where = " in " + func + "()"
except IndexError: except IndexError:
file, line, where = "/<UNKNOWN>", 0, "" file, line, where = "/<UNKNOWN>", 0, ""
_flushfunc()
_logfunc("ietf%s(%d)%s: %s" % (file, line, where, msg))
logger = logging.getLogger('django')
logging.getLogger("datatracker").info(msg=msg, extra = {"file":file, "line":line, "where":where})
def exc_parts(): def exc_parts():
@ -124,6 +83,7 @@ def assertion(statement, state=True, note=None):
This acts like an assertion. It uses the django logger in order to send This acts like an assertion. It uses the django logger in order to send
the failed assertion and a backtrace as for an internal server error. the failed assertion and a backtrace as for an internal server error.
""" """
logger = logging.getLogger("django") # Note this is a change - before this would have gone to "django"
frame = inspect.currentframe().f_back frame = inspect.currentframe().f_back
value = eval(statement, frame.f_globals, frame.f_locals) value = eval(statement, frame.f_globals, frame.f_locals)
if bool(value) != bool(state): if bool(value) != bool(state):
@ -148,6 +108,7 @@ def assertion(statement, state=True, note=None):
def unreachable(date="(unknown)"): def unreachable(date="(unknown)"):
"Raises an assertion or sends traceback to admins if executed." "Raises an assertion or sends traceback to admins if executed."
logger = logging.getLogger("django")
frame = inspect.currentframe().f_back frame = inspect.currentframe().f_back
if settings.DEBUG is True or settings.SERVER_MODE == 'test': if settings.DEBUG is True or settings.SERVER_MODE == 'test':
raise AssertionError("Arrived at code in %s() which was marked unreachable on %s." % (frame.f_code.co_name, date)) raise AssertionError("Arrived at code in %s() which was marked unreachable on %s." % (frame.f_code.co_name, date))

View file

@ -11,18 +11,7 @@ from django.core.management.base import BaseCommand
import debug # pyflakes:ignore import debug # pyflakes:ignore
class Command(BaseCommand): class Command(BaseCommand):
""" """Display a list or tree representation of python loggers"""
Display a list or tree representation of python loggers.
Add a UTILS_LOGGER_LEVELS setting in settings_local.py to configure
non-default logging levels for any registered logger, for instance:
UTILS_LOGGER_LEVELS = {
'oicd_provider': 'DEBUG',
'urllib3.connection': 'DEBUG',
}
"""
help = dedent(__doc__).strip() help = dedent(__doc__).strip()

View file

@ -53,6 +53,7 @@ pyopenssl>=22.0.0 # Used by urllib3.contrib, which is used by PyQuery but not
pyquery>=1.4.3 pyquery>=1.4.3
python-dateutil>=2.8.2 python-dateutil>=2.8.2
types-python-dateutil>=2.8.2 types-python-dateutil>=2.8.2
python-json-logger>=2.0.7
python-magic==0.4.18 # Versions beyond the yanked .19 and .20 introduce form failures python-magic==0.4.18 # Versions beyond the yanked .19 and .20 introduce form failures
pymemcache>=4.0.0 # for django.core.cache.backends.memcached.PyMemcacheCache pymemcache>=4.0.0 # for django.core.cache.backends.memcached.PyMemcacheCache
python-mimeparse>=1.6 # from TastyPie python-mimeparse>=1.6 # from TastyPie