Skip to content

Commit

Permalink
fix: Avoid using a Gunicorn config file
Browse files Browse the repository at this point in the history
  • Loading branch information
khvn26 committed Mar 28, 2024
1 parent ee1c396 commit 11d793f
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 20 deletions.
5 changes: 4 additions & 1 deletion api/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@ django-collect-static:

.PHONY: serve
serve:
poetry run gunicorn --bind 0.0.0.0:8000 app.wsgi --reload
poetry run gunicorn --bind 0.0.0.0:8000 \
--logger-class ${GUNICORN_LOGGER_CLASS:-'util.logging.GunicornJsonCapableLogger'} \
--reload \
app.wsgi

.PHONY: generate-ld-client-types
generate-ld-client-types:
Expand Down
3 changes: 2 additions & 1 deletion api/scripts/run-docker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ function serve() {
--workers ${GUNICORN_WORKERS:-3} \
--threads ${GUNICORN_THREADS:-2} \
--access-logfile $ACCESS_LOG_LOCATION \
--access-logformat '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %({origin}i)s %({access-control-allow-origin}o)s' \
--logger-class ${GUNICORN_LOGGER_CLASS:-'util.logging.GunicornJsonCapableLogger'} \
--access-logformat ${ACCESS_LOG_FORMAT:-'%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %({origin}i)s %({access-control-allow-origin}o)s'} \
--keep-alive ${GUNICORN_KEEP_ALIVE:-2} \
${STATSD_HOST:+--statsd-host $STATSD_HOST:$STATSD_PORT} \
${STATSD_HOST:+--statsd-prefix $STATSD_PREFIX} \
Expand Down
77 changes: 59 additions & 18 deletions api/util/logging.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,68 @@
import json
import logging
import sys
from datetime import datetime
from typing import Any

from django.conf import settings
from gunicorn.config import Config
from gunicorn.glogging import Logger as GunicornLogger


class JsonFormatter(logging.Formatter):
"""Custom formatter for json logs."""

def format(self, record):
"""
%s is replaced with {} because legacy string formatting
conventions in django-axes module prevent correct
interpolation of arguments when using this formatter.
"""
def get_json_record(self, record: logging.LogRecord) -> dict[str, Any]:
formatted_message = record.getMessage()
return {
"levelname": record.levelname,
"message": formatted_message,
"timestamp": self.formatTime(record, self.datefmt),
"logger_name": record.name,
"process_id": record.process,
"thread_name": record.threadName,
}

def format(self, record: logging.LogRecord) -> str:
try:
log_message = record.msg.replace("%s", "{}")
formatted_message = log_message.format(*record.args)
log_record = {
"levelname": record.levelname,
"message": formatted_message,
"timestamp": self.formatTime(record, self.datefmt),
"logger_name": record.name,
"process_id": record.process,
"thread_name": record.threadName,
}
return json.dumps(log_record)
return json.dumps(self.get_json_record(record))
except (ValueError, TypeError) as e:
return f"Error formatting log record: {str(e)}"
return json.dumps({"message": f"{e} when dumping log"})


class GunicornAccessLogJsonFormatter(JsonFormatter):
def get_json_record(self, record: logging.LogRecord) -> dict[str, Any]:
response_time = datetime.strptime(record.args["t"], "[%d/%b/%Y:%H:%M:%S %z]")
url = record.args["U"]
if record.args["q"]:
url += f"?{record.args['q']}"

return {
**super().get_json_record(record),
"time": response_time.isoformat(),
"path": url,
"remote_ip": record.args["h"],
"method": record.args["m"],
"status": str(record.args["s"]),
"user_agent": record.args["a"],
"referer": record.args["f"],
"duration_in_ms": record.args["M"],
"pid": record.args["p"],
}


class GunicornJsonCapableLogger(GunicornLogger):
def setup(self, cfg: Config) -> None:
super().setup(cfg)
if settings.LOG_FORMAT == "json":
self._set_handler(
self.error_log,
cfg.errorlog,
JsonFormatter(),
)
self._set_handler(
self.access_log,
cfg.accesslog,
GunicornAccessLogJsonFormatter(),
stream=sys.stdout,
)

0 comments on commit 11d793f

Please sign in to comment.