diff --git a/Dockerfile b/Dockerfile index edd01f00..e225bb3e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,28 +18,36 @@ ENV STATIC_ROOT /srv/static # while in Docker. Maybe the buffer is larger? ENV PYTHONUNBUFFERED True +COPY requirements.txt /app/ +COPY requirements-prod.txt /app/ +COPY deploy/escape_json.c /app/deploy/escape_json.c + # less & netcat-openbsd are there for in-container manual debugging # kerrokantasi needs gdal -RUN apt-get update && apt-get install -y postgresql-client less netcat-openbsd gettext locales gdal-bin python3-gdal - -# we need the Finnish locale built -RUN sed -i 's/^# *\(fi_FI.UTF-8\)/\1/' /etc/locale.gen -RUN locale-gen - -RUN pip install --upgrade pip setuptools wheel && \ - pip install --no-cache-dir uwsgi +RUN apt-get update \ + && apt-get install -y \ + build-essential \ + postgresql-client \ + less \ + netcat-openbsd \ + gettext \ + locales \ + gdal-bin \ + python3-gdal \ + # Build finnish locale + && sed -i 's/^# *\(fi_FI.UTF-8\)/\1/' /etc/locale.gen \ + && locale-gen \ + && pip install --upgrade pip setuptools wheel \ + && pip install --no-cache-dir -r /app/requirements.txt \ + && pip install --no-cache-dir -r /app/requirements-prod.txt \ + && uwsgi --build-plugin /app/deploy/escape_json.c \ + && mv /app/escape_json_plugin.so /app/deploy/escape_json_plugin.so \ + && apt-get remove -y build-essential # Sentry CLI for sending events from non-Python processes to Sentry # eg. https://docs.sentry.io/cli/send-event/#bash-hook RUN curl -sL https://sentry.io/get-cli/ | bash -# Copy requirements files to image for preloading dependencies -# in their own layer -COPY requirements.txt ./ - -# deploy/requirements.txt must reference the base requirements -RUN pip install --no-cache-dir -r requirements.txt - COPY . . # Statics are kept inside container image for serving using whitenoise diff --git a/deploy/escape_json.c b/deploy/escape_json.c new file mode 100644 index 00000000..f9943c7b --- /dev/null +++ b/deploy/escape_json.c @@ -0,0 +1,42 @@ +/* + https://github.com/velebit-ai/uwsgi-json-logging-plugin/blob/4edb5cc59013b18f32658195b328afb2ac21b2d2/escape_json.c + uWSGI plugin that creates custom json-escaped logging variables. + build plugin with `uwsgi --build-plugin ` + and use it with `uwsgi --plugin ...` +*/ +#include + + +static ssize_t uwsgi_lf_json_uri(struct wsgi_request *wsgi_req, char **buf) { + long pos = offsetof(struct wsgi_request, uri); + long pos_len = offsetof(struct wsgi_request, uri_len); + char **var = (char **) (((char *) wsgi_req) + pos); + uint16_t *varlen = (uint16_t *) (((char *) wsgi_req) + pos_len); + + char *e_json = uwsgi_malloc((*varlen * 2) + 1); + escape_json(*var, *varlen, e_json); + *buf = e_json; + return strlen(*buf); +} + +static ssize_t uwsgi_lf_json_host(struct wsgi_request *wsgi_req, char **buf) { + long pos = offsetof(struct wsgi_request, host); + long pos_len = offsetof(struct wsgi_request, host_len); + char **var = (char **) (((char *) wsgi_req) + pos); + uint16_t *varlen = (uint16_t *) (((char *) wsgi_req) + pos_len); + + char *e_json = uwsgi_malloc((*varlen * 2) + 1); + escape_json(*var, *varlen, e_json); + *buf = e_json; + return strlen(*buf); +} + +static void register_logchunks() { + uwsgi_register_logchunk("json_uri", uwsgi_lf_json_uri, 1); + uwsgi_register_logchunk("json_host", uwsgi_lf_json_host, 1); +} + +struct uwsgi_plugin escape_json_plugin = { + .name = "escape_json", + .on_load = register_logchunks, +}; diff --git a/deploy/uwsgi.yml b/deploy/uwsgi.yml index e825878b..43520a65 100644 --- a/deploy/uwsgi.yml +++ b/deploy/uwsgi.yml @@ -1,4 +1,5 @@ uwsgi: + plugin: /app/deploy/escape_json_plugin.so # Needed plugins if running against Debian uwsgi-package # python docker image cannot use that due to linker mishaps # plugins: python3,http @@ -20,3 +21,8 @@ uwsgi: ignore-sigpipe: true ignore-write-errors: true disable-write-exception: true + + logger-req: stdio + remote_addr: "%(addr)", "x_forwarded_for":"%(var.HTTP_X_FORWARDED_FOR)", "request_id":"%(var.HTTP_X_REQUEST_ID)", "remote_user":"%(user)", "bytes_sent":%(size), "request_time":%(secs), "status":%(status), "host":"%(json_host)", "request_proto":"%(proto)", "path":"%(json_uri)", "request_length":%(cl), "http_referer":"%(referer)", "http_user_agent":"%(uagent)" + log-req-encoder: format {"time":"${strftime:%%Y:%%m:%%d %%H:%%M:%%S}", "source":"uwsgi-req", ${msg}} + log-req-encoder: nl