Skip to content

Commit b36ff61

Browse files
rjsparksNGPixel
authored andcommitted
feat: use gunicorn (ietf-tools#7215)
* feat: use gunicorn * fix: let gunicorn emit logs to stdout/stderr * fix: log to stdout/stderr in json format * fix: run collectstatic for the local copy of the statics
1 parent f1e6c37 commit b36ff61

4 files changed

Lines changed: 39 additions & 47 deletions

File tree

dev/build/datatracker-start.sh

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,19 @@ echo "Running Datatracker checks..."
66
echo "Running Datatracker migrations..."
77
./ietf/manage.py migrate --settings=settings_local
88

9+
echo "Running collectstatic..."
10+
./ietf/manage.py collectstatic
11+
912
echo "Starting Datatracker..."
10-
./ietf/manage.py runserver 0.0.0.0:8000 --settings=settings_local
13+
14+
gunicorn \
15+
--workers 53 \
16+
--max-requests 32768 \
17+
--timeout 180 \
18+
--bind :8000 \
19+
--log-level info \
20+
ietf.wsgi:application
21+
22+
# Leaving this here as a reminder to set up the env in the chart
23+
# Remove this once that's complete.
24+
#--env SCOUT_NAME=Datatracker \

ietf/settings.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ def skip_unreadable_post(record):
236236
#
237237
'loggers': {
238238
'django': {
239-
'handlers': ['debug_console', 'mail_admins'],
239+
'handlers': ['console', 'mail_admins',],
240240
'level': 'INFO',
241241
},
242242
'django.request': {
@@ -248,13 +248,17 @@ def skip_unreadable_post(record):
248248
'level': 'INFO',
249249
},
250250
'django.security': {
251-
'handlers': ['debug_console', ],
251+
'handlers': ['console', ],
252+
'level': 'INFO',
253+
},
254+
'oidc_provider': {
255+
'handlers': ['debug_console', ],
256+
'level': 'DEBUG',
257+
},
258+
'datatracker': {
259+
'handlers': ['console', ],
252260
'level': 'INFO',
253261
},
254-
'oidc_provider': {
255-
'handlers': ['debug_console', ],
256-
'level': 'DEBUG',
257-
},
258262
},
259263
#
260264
# No logger filters
@@ -263,14 +267,7 @@ def skip_unreadable_post(record):
263267
'console': {
264268
'level': 'DEBUG',
265269
'class': 'logging.StreamHandler',
266-
'formatter': 'plain',
267-
},
268-
'syslog': {
269-
'level': 'DEBUG',
270-
'class': 'logging.handlers.SysLogHandler',
271-
'facility': 'user',
272-
'formatter': 'plain',
273-
'address': '/dev/log',
270+
'formatter': 'json',
274271
},
275272
'debug_console': {
276273
# Active only when DEBUG=True
@@ -325,6 +322,9 @@ def skip_unreadable_post(record):
325322
'style': '{',
326323
'format': '{levelname}: {name}:{lineno}: {message}',
327324
},
325+
'json' : {
326+
'()': 'pythonjsonlogger.jsonlogger.JsonFormatter'
327+
}
328328
},
329329
}
330330

ietf/utils/log.py

Lines changed: 9 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,19 @@
1010
import traceback
1111

1212
from typing import Callable # pyflakes:ignore
13-
14-
try:
15-
import syslog
16-
logfunc = syslog.syslog # type: Callable
17-
except ImportError: # import syslog will fail on Windows boxes
18-
logging.basicConfig(filename='tracker.log',level=logging.INFO)
19-
logfunc = logging.info
20-
pass
21-
2213
from django.conf import settings
14+
from pythonjsonlogger import jsonlogger
2315

2416
import debug # pyflakes:ignore
2517

26-
formatter = logging.Formatter('{levelname}: {name}:{lineno}: {message}', style='{')
18+
formatter = jsonlogger.JsonFormatter
2719
for name, level in settings.UTILS_LOGGER_LEVELS.items():
2820
logger = logging.getLogger(name)
2921
if not logger.hasHandlers():
3022
debug.say(' Adding handlers to logger %s' % logger.name)
31-
3223
handlers = [
33-
logging.StreamHandler(),
34-
logging.handlers.SysLogHandler(address='/dev/log',
35-
facility=logging.handlers.SysLogHandler.LOG_USER),
36-
]
24+
logging.StreamHandler(),
25+
]
3726
for h in handlers:
3827
h.setFormatter(formatter)
3928
h.setLevel(level)
@@ -56,20 +45,9 @@ def getcaller():
5645
return (pmodule, pclass, pfunction, pfile, pline)
5746

5847
def log(msg, e=None):
59-
"Uses syslog by preference. Logs the given calling point and message."
60-
global logfunc
61-
def _flushfunc():
62-
pass
63-
_logfunc = logfunc
64-
if settings.SERVER_MODE == 'test':
65-
if getattr(settings, 'show_logging', False) is True:
66-
_logfunc = debug.say
67-
_flushfunc = sys.stdout.flush # pyflakes:ignore (intentional redefinition)
68-
else:
48+
"Logs the given calling point and message to the logging framework's datatracker handler at severity INFO"
49+
if settings.SERVER_MODE == 'test' and not getattr(settings, 'show_logging',False):
6950
return
70-
elif settings.DEBUG == True:
71-
_logfunc = debug.say
72-
_flushfunc = sys.stdout.flush # pyflakes:ignore (intentional redefinition)
7351
if not isinstance(msg, str):
7452
msg = msg.encode('unicode_escape')
7553
try:
@@ -82,11 +60,8 @@ def _flushfunc():
8260
where = " in " + func + "()"
8361
except IndexError:
8462
file, line, where = "/<UNKNOWN>", 0, ""
85-
_flushfunc()
86-
_logfunc("ietf%s(%d)%s: %s" % (file, line, where, msg))
87-
88-
logger = logging.getLogger('django')
8963

64+
logging.getLogger("datatracker").info(msg=msg, extra = {"file":file, "line":line, "where":where})
9065

9166

9267
def exc_parts():
@@ -124,6 +99,7 @@ def assertion(statement, state=True, note=None):
12499
This acts like an assertion. It uses the django logger in order to send
125100
the failed assertion and a backtrace as for an internal server error.
126101
"""
102+
logger = logging.getLogger("django") # Note this is a change - before this would have gone to "django"
127103
frame = inspect.currentframe().f_back
128104
value = eval(statement, frame.f_globals, frame.f_locals)
129105
if bool(value) != bool(state):
@@ -148,6 +124,7 @@ def assertion(statement, state=True, note=None):
148124

149125
def unreachable(date="(unknown)"):
150126
"Raises an assertion or sends traceback to admins if executed."
127+
logger = logging.getLogger("django")
151128
frame = inspect.currentframe().f_back
152129
if settings.DEBUG is True or settings.SERVER_MODE == 'test':
153130
raise AssertionError("Arrived at code in %s() which was marked unreachable on %s." % (frame.f_code.co_name, date))

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ pyopenssl>=22.0.0 # Used by urllib3.contrib, which is used by PyQuery but not
5353
pyquery>=1.4.3
5454
python-dateutil>=2.8.2
5555
types-python-dateutil>=2.8.2
56+
python-json-logger>=2.0.7
5657
python-magic==0.4.18 # Versions beyond the yanked .19 and .20 introduce form failures
5758
pymemcache>=4.0.0 # for django.core.cache.backends.memcached.PyMemcacheCache
5859
python-mimeparse>=1.6 # from TastyPie

0 commit comments

Comments
 (0)