From de9809a9e57bef9f2025a382ce7baa040b9cab30 Mon Sep 17 00:00:00 2001 From: Denis Arh Date: Tue, 14 Mar 2023 12:11:33 +0100 Subject: [PATCH] Add more control over log_format config directive Introduces 3 new environmental variables: - `LOG_FORMAT` - `LOG_FORMAT_ESCAPE` - `LOG_JSON` `LOG_FORMAT` and `LOG_FORMAT_ESCAPE` default to standard values. When `LOG_JSON` is set, defaults are changed to: `{"time_local":"$time_iso8601","client_ip":"$http_x_forwarded_for","remote_addr":"$remote_addr","request":"$request","status":"$status","body_bytes_sent":"$body_bytes_sent","request_time":"$request_time","upstream_response_time":"$upstream_response_time","upstream_addr":"$upstream_addr","http_referrer":"$http_referer","http_user_agent":"$http_user_agent","request_id":"$request_id"}`and `json`. See `nginx.tmpl` and https://nginx.org/en/docs/http/ngx_http_log_module.html#log_format for details --- nginx.tmpl | 19 ++++++++++++++++++- test/test_log_json.py | 14 ++++++++++++++ test/test_log_json.yml | 15 +++++++++++++++ test/test_log_json_format.py | 16 ++++++++++++++++ test/test_log_json_format.yml | 15 +++++++++++++++ 5 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 test/test_log_json.py create mode 100644 test/test_log_json.yml create mode 100644 test/test_log_json_format.py create mode 100644 test/test_log_json_format.yml diff --git a/nginx.tmpl b/nginx.tmpl index 8b8b12e..5405e7e 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -402,7 +402,24 @@ map $proxy_x_forwarded_proto $proxy_x_forwarded_ssl { gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; -log_format vhost '{{ or $globals.Env.LOG_FORMAT "$host $remote_addr - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\" \"$upstream_addr\"" }}'; + +{{- /* See https://nginx.org/en/docs/http/ngx_http_log_module.html#log_format for details and variables + * LOG_FORMAT_ESCAPE sets the escape part of the log format + * LOG_FORMAT sets the log format + */}} +{{- $logEscape := printf "escape=%s" ( or $globals.Env.LOG_FORMAT_ESCAPE `default`) }} +{{- $logFormat := (or $globals.Env.LOG_FORMAT `$host $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$upstream_addr"`) }} + +{{- if $globals.Env.LOG_JSON }} +{{- /* LOG_JSON is a shorthand + * that sets logging defaults to JSON format + */}} +# JSON Logging enabled (via LOG_JSON env variable) +{{- $logEscape = printf "escape=%s" ( or $globals.Env.LOG_FORMAT_ESCAPE `json`) }} +{{- $logFormat = (or $globals.Env.LOG_FORMAT `{"time_local":"$time_iso8601","client_ip":"$http_x_forwarded_for","remote_addr":"$remote_addr","request":"$request","status":"$status","body_bytes_sent":"$body_bytes_sent","request_time":"$request_time","upstream_response_time":"$upstream_response_time","upstream_addr":"$upstream_addr","http_referrer":"$http_referer","http_user_agent":"$http_user_agent","request_id":"$request_id"}`) }} +{{- end }} + +log_format vhost {{ $logEscape }} '{{ or $globals.Env.LOG_FORMAT $logFormat }}'; access_log off; diff --git a/test/test_log_json.py b/test/test_log_json.py new file mode 100644 index 0000000..1a04b22 --- /dev/null +++ b/test/test_log_json.py @@ -0,0 +1,14 @@ +import pytest + +def test_log_json(docker_compose, nginxproxy): + log_conf = [line for line in nginxproxy.get_conf().decode('ASCII').splitlines() if "log_format vhost escape=" in line] + assert "{\"time_local\":\"$time_iso8601\"," in log_conf[0] + + r = nginxproxy.get("http://nginx-proxy.test/port") + assert r.status_code == 200 + assert r.text == "answer from port 81\n" + sut_container = docker_compose.containers.get("sut") + docker_logs = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False) + docker_logs = docker_logs.decode("utf-8").splitlines() + docker_logs = [line for line in docker_logs if "{\"time_local\":" in line] + assert "GET /port" in docker_logs[0] diff --git a/test/test_log_json.yml b/test/test_log_json.yml new file mode 100644 index 0000000..7740191 --- /dev/null +++ b/test/test_log_json.yml @@ -0,0 +1,15 @@ +web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: 81 + VIRTUAL_HOST: nginx-proxy.test + +sut: + container_name: sut + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + environment: + LOG_JSON: 1 diff --git a/test/test_log_json_format.py b/test/test_log_json_format.py new file mode 100644 index 0000000..56cfdea --- /dev/null +++ b/test/test_log_json_format.py @@ -0,0 +1,16 @@ +import pytest + +def test_log_json_format(docker_compose, nginxproxy): + log_conf = [line for line in nginxproxy.get_conf().decode('ASCII').splitlines() if "log_format vhost escape=" in line] + assert "{\"time_local\":\"$time_iso8601\"," in log_conf[0] + + r = nginxproxy.get("http://nginx-proxy.test/port") + assert r.status_code == 200 + assert r.text == "answer from port 81\n" + sut_container = docker_compose.containers.get("sut") + docker_logs = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False) + docker_logs = docker_logs.decode("utf-8").splitlines() + docker_logs = [line for line in docker_logs if "{\"time_local\":" in line] + assert "GET /port" in docker_logs[0] + + diff --git a/test/test_log_json_format.yml b/test/test_log_json_format.yml new file mode 100644 index 0000000..caf20a7 --- /dev/null +++ b/test/test_log_json_format.yml @@ -0,0 +1,15 @@ +web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: 81 + VIRTUAL_HOST: nginx-proxy.test + +sut: + container_name: sut + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + environment: + LOG_FORMAT: '{"time_local":"$$time_iso8601","remote_addr":"$$remote_addr","request":"$$request","upstream_addr":"$$upstream_addr"}'